package com.yanqu.road.server.gameplayer.module.cricket;

import com.yanqu.road.dao.dbV2.serializer.Helper;
import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityConditionInfo;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.UserActivityConditionData;
import com.yanqu.road.entity.config.badge.BadgeConfig;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.MallInfo;
import com.yanqu.road.entity.config.goods.MallWheelResult;
import com.yanqu.road.entity.config.patrons.PatronsInfo;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.config.skill.SkillUpgradeInfo;
import com.yanqu.road.entity.cricket.*;
import com.yanqu.road.entity.cricket.config.*;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.language.LanguageType;
import com.yanqu.road.entity.log.*;
import com.yanqu.road.entity.player.*;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.servercenter.group.CricketServerGroup;
import com.yanqu.road.entity.task.args.CricketItemArgs;
import com.yanqu.road.entity.task.args.CricketTiTleArgs;
import com.yanqu.road.logic.bussiness.player.UserActivityBussiness;
import com.yanqu.road.logic.bussiness.player.UserCricketBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.cricket.CricketProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.ActivityModule;
import com.yanqu.road.server.gameplayer.module.activity.rankunionwar.RankUnionWarModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.cricket.entity.DbUserCricketBattleLog;
import com.yanqu.road.server.gameplayer.module.cricket.entity.DbUserCricketWaitSendBattleLog;
import com.yanqu.road.server.gameplayer.module.cricket.entity.business.CricketGameBusiness;
import com.yanqu.road.server.gameplayer.module.cricket.model.CricketBattleData;
import com.yanqu.road.server.gameplayer.module.cricket.model.LogCricket;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.player.*;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.manger.CricketServerGroupMgr;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.MallActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.rankunionwar.RankUnionWarMgr;
import com.yanqu.road.server.manger.activity.strongholdwar.StrongholdActivityMgr;
import com.yanqu.road.server.manger.activity.unionwar.UnionPhaseWarMgr;
import com.yanqu.road.server.manger.config.*;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.maidian.cricket.CricketLog;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.rank.RankMgr;
import com.yanqu.road.server.pb.CricketPb;
import com.yanqu.road.server.pb.PlayerPb;
import com.yanqu.road.server.protocol.*;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 蛐蛐系统
 */
public class CricketModule extends GeneralModule {

    private static Logger logger = LogManager.getLogger(CricketModule.class.getName());

    /**
     * 用户数据
     */
    private UserCricketData userCricketData;

    /**
     * 用户蛐蛐数据
     */
    private Map<Integer, CricketData> cricketDataMap = new ConcurrentHashMap<>();

    /**
     * 用户图鉴数据
     */
    private Map<Integer, CricketBookData> bookDataMap = new ConcurrentHashMap<>();

    private Map<Integer, PatronsCricketBindingData> patronsCricketBindingDataMap;


    private final List<DbUserCricketBattleLog> cricketBattleLogList = new ArrayList<>();

    private RandomHelper randomHelper = new RandomHelper();

    public CricketModule(GamePlayer player) {
        super(player);
    }

    public void sendSelf(String content){
        if(ServerListMgr.getChannelId(GameServer.getInstance().getServerId()) != 666){
            return;
        }
        if(content.equals("26338")){
            CricketProto.EquipCricketReqMsg.Builder reqMsg = CricketProto.EquipCricketReqMsg.newBuilder();
            for(CricketData data : cricketDataMap.values()){
                CricketConfig cricketConfig = CricketMgr.getConfig().getCricketConfig(data.getCricketId());
                if (GameConfig.CRICKET_EQUIP_CRICKET_QUALITY_LIMIT <= cricketConfig.getQuality()) {
                    reqMsg.setCricketId(data.getCricketId());
                    reqMsg.setPatronsId(102120);
                    player.sendPacket(Protocol.S_CRICKET_EQUIP_CRICKET, reqMsg);
                    break;
                }
            }
        }
        if(content.equals("26340")){
            CricketProto.CricketSkillUpReqMsg.Builder reqMsg = CricketProto.CricketSkillUpReqMsg.newBuilder();
            for(CricketData data : cricketDataMap.values()){
                if (data.getEquipSkillList().size() > 0) {
                    reqMsg.setCricketId(data.getCricketId());
                    reqMsg.setSkillId(data.getEquipSkillList().get(0).getSkillId());
                    player.sendPacket(Protocol.S_CRICKET_SKILL_UP, reqMsg);
                    break;
                }
            }
        }
        if(content.equals("26341")){
            CricketProto.CricketActivityWarTimesReqMsg.Builder reqMsg = CricketProto.CricketActivityWarTimesReqMsg.newBuilder();
            ActivityInfo activityInfo = RankUnionWarMgr.getActivity();
            if(activityInfo != null){
                reqMsg.setActivityId(activityInfo.getActivityId());
                reqMsg.setActivityType(activityInfo.getType());
                player.sendPacket(Protocol.S_CRICKET_ACTIVITY_WAR_TIMES, reqMsg);
            }
        }
        if(content.equals("26342")){
            CricketProto.CricketGetRelationMessageReqMsg.Builder reqMsg = CricketProto.CricketGetRelationMessageReqMsg.newBuilder();
            ActivityInfo activityInfo = RankUnionWarMgr.getActivity();
            if(activityInfo != null){
                player.sendPacket(Protocol.S_CRICKET_GET_REWARD_RELATION, reqMsg);
            }
        }
    }

    //加载通用技能
    private void loadEquipSkill(){
        Map<Integer, List<CricketEquipSkill>> eSkillMap = UserCricketBussiness.getCricketEquipSkillMap(player.getUserId());
        for(Integer cricketId : eSkillMap.keySet()){
            if(cricketDataMap.containsKey(cricketId)){
                cricketDataMap.get(cricketId).setEquipSkillList(eSkillMap.get(cricketId));
            }
        }
    }

    @Override
    public boolean loadData() {
        // 加载用户数据
        userCricketData = UserCricketBussiness.getUserCricketData(player.getUserId());
        // 加载用户蛐蛐数据
        cricketDataMap = UserCricketBussiness.getCricketDataMap(player.getUserId());
        // 加载用户图鉴信息
        bookDataMap = UserCricketBussiness.getCricketBookDataMap(player.getUserId());

        patronsCricketBindingDataMap = UserCricketBussiness.getCricketBindDataMap(player.getUserId());

        loadEquipSkill();

        loadBattleLog();
        return true;
    }

    private void loadBattleLog() {
        int limit = GameConfig.CRICKET_FIGHT_REPORT_MY_MAX_NUM;
        Map<Long, DbUserCricketBattleLog> dbUserCricketBattleLogMap = CricketGameBusiness.getDbUserCricketBattleLogMap(player.getUserId(), limit);
        for (DbUserCricketBattleLog dbUserCricketBattleLog : dbUserCricketBattleLogMap.values()) {
            addDbCricketBattleLog(dbUserCricketBattleLog);
        }
//        cricketBattleLogList.sort(Comparator.comparing(DbUserCricketBattleLog::getCreateTime).reversed());
    }

    @Override
    public void loginSendMsg() {
        // 初始化用户信息
        initUserData();
        // 重新计算蛐蛐属性
        reCheckCricketData();
        // 初始化竞技场勋章
        initCricketCourtBadge();
        // 同步数据
        syncData();
    }

    @Override
    public void afterLogin() {

        // 同步下配置
        syncConfig();

        UserCricketData userCricketData1 = this.getUserCricketData();
        //这里恢复匹配的的道具

        Property preReduceProperty = userCricketData1.getCricketMatchData().getPreReduceProperty();
        if (preReduceProperty != null) {
            userCricketData1.getCricketMatchData().setPreReduceProperty(null);
            userCricketData1.setUpdateOption();
        }
        addCricketFateValue();

        syncPatronsBindMsg(patronsCricketBindingDataMap.values());

        // 检查下战令状态
        checkToken();

        syncCrossCricketData();
    }

    /**
     * 检查战令
     */
    public void checkToken() {
        CricketSystemConfig config = CricketMgr.getConfig();
        ActivityInfo activityInfo = config.getActivityInfo();
        if (!ActivityHelper.activityInTime(activityInfo)) {
            return;
        }
        // 计算当前为第几天
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        MallWheelResult wheelResult = MallActivityMgr.calWheel(activityInfo, serverInfo);
        int tokenRound = wheelResult.getGapDay() / config.getTokenResetTime() + 1;
        if (null != userCricketData && tokenRound != userCricketData.getTokenRound()) {
            // 补发奖励
            List<Integer> conditionTypeList = new ArrayList<>();
            conditionTypeList.add(eGamePlayerEventType.CricketCourtBronzeToken.getValue());
            conditionTypeList.add(eGamePlayerEventType.CricketCourtSliverToken.getValue());
            conditionTypeList.add(eGamePlayerEventType.CricketCourtGoldToken.getValue());
            sendTokenReward(activityInfo, conditionTypeList);
            // 重置
            resetToken();
            userCricketData.setTokenRound(tokenRound);
            // 同步下用户数据
            syncUserData();
        }
    }

    /**
     * 每日重置
     */
    public void resetOneDay(){
        checkToken();
    }

    /**
     * 补发战令成就奖励
     */
    private void sendTokenReward(ActivityInfo activityInfo, List<Integer> conditionTypeList) {
        List<UserActivityConditionData> conditionDataList = new ArrayList<>();
        for (Integer conditionType : conditionTypeList) {
            conditionDataList.addAll(UserActivityBussiness.getUserActivityConditionDataListByUserIdAndType(activityInfo.getActivityId(), player.getUserId(), conditionType));
        }
        Property reward = new Property();
        for (UserActivityConditionData conditionData : conditionDataList) {
            if (conditionData.isGetReward()) {
                continue;
            }
            ActivityConditionInfo activityConditionInfo = NormalActivityMgr.getActivityConditionInfo(activityInfo.getActivityId(), conditionData.getConditionId());
            if (activityConditionInfo == null) {
                logger.info("auto send activity condition reward conditionInfo is null, activityId:{},userId:{},conditionId:{}", activityInfo.getActivityId(), conditionData.getUserId(), conditionData.getConditionId());
                continue;
            }
            int conditionId = activityConditionInfo.getConditionId();
            if (conditionData.getValue().compareTo(activityConditionInfo.getParamList().get(3)) < 0) {
                continue;
            }
            conditionData.setGetReward(true);
            if (!UserActivityBussiness.updateUserActivityConditionDataState(conditionData)) {
                logger.error("auto send activity reward save db fail, activityId:{},userId:{},conditionId:{}", activityInfo.getActivityId(), conditionData.getUserId(), conditionData.getConditionId());
                continue;
            }
            reward.addProperty(PropertyHelper.parseStringToProperty(activityConditionInfo.getRewardStr()));
            LogMgr.addLogActivityReward(player.getUserId(), activityInfo.getActivityId(), activityInfo.getType(), activityInfo.getChildType(),
                    conditionId, 0, true, activityConditionInfo.getRewardStr());
        }
        if (reward.isNothing()) {
            return;
        }
        UserInfo userInfo = UserMgr.getUserInfo(player.getUserId());
        String language = LanguageType.LANGUAGE_DEFAULT;
        if (null != userInfo) {
            language = userInfo.getLanguage();
        }
        // 发邮件
        String mailTitle = MultipleLanguageMgr.getContent(MailManager.CRICKET_FIGHT_TOKEN_REWARD_TITLE, language);
        String mailContent = MultipleLanguageMgr.getContent(MailManager.CRICKET_FIGHT_TOKEN_REWARD_CONTENT, language);
        MailManager.sendMail(player.getUserId(), eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(reward), mailContent, mailTitle);
    }


    public void syncCrossCricketData() {
        CricketProto.CrossCricketSyncDataReqMsg.Builder reqMsg = CricketProto.CrossCricketSyncDataReqMsg.newBuilder();
        player.sendPacket(Protocol.C_CROSS_CRICKET_SYNC_DATA, reqMsg);
    }

    public void addPatronsBindData(int activityId, int patronsId, int cricketId) {
        PatronsCricketBindingData data = patronsCricketBindingDataMap.get(cricketId);
        if (data == null) {
            data = new PatronsCricketBindingData();
            data.setCricketId(cricketId);
            data.setInsertOption();
            data.setUserId(getUserId());
            patronsCricketBindingDataMap.put(cricketId, data);
        }
        data.setPatronsId(patronsId);
        data.addActivityId(activityId);
        data.setLastUpdateTime(System.currentTimeMillis());
        syncPatronsBindMsg(Collections.singletonList(data));
    }

    public void addPatronsBindSystem(int systemId, int patronsId, int cricketId, long endTime) {
        PatronsCricketBindingData data = patronsCricketBindingDataMap.get(cricketId);
        if (data == null) {
            data = new PatronsCricketBindingData();
            data.setCricketId(cricketId);
            data.setInsertOption();
            data.setUserId(getUserId());
            patronsCricketBindingDataMap.put(cricketId, data);
        }
        data.setPatronsId(patronsId);
        data.addSystem(systemId, endTime);
        data.setLastUpdateTime(System.currentTimeMillis());
        syncPatronsBindMsg(Collections.singletonList(data));
    }

    private void syncPatronsBindMsg(Collection<PatronsCricketBindingData> dataList) {
        CricketProto.SyncPatronsCricketBindingMsg.Builder syncMsg = CricketProto.SyncPatronsCricketBindingMsg.newBuilder();
        for (PatronsCricketBindingData data : dataList) {
            CricketProto.PatronsCricketBindingMsg.Builder msg = CricketProto.PatronsCricketBindingMsg.newBuilder();
            msg.setCricketId(data.getCricketId());
            msg.setPatronsId(data.getPatronsId());
            msg.setActivityId(0);
            if (data.getActivityIdList().size() > 0) {
                msg.setActivityId(data.getActivityIdList().get(0));
            }
            if (data.getSystemId() > 0) {
                msg.setSystemId(data.getSystemId());
                msg.setSystemEndTime(data.getSystemEndTime());
            }
            syncMsg.addData(msg);
        }
        player.sendPacket(ClientProtocol.U_CRICKET_ACTIVITY_PATRONS_BIND, syncMsg);
    }

    public int equipCricket(int crickedId,int patronsId){
        if(crickedId == 0){
            disEquipCricket(patronsId);
            return 0;
        }
        CricketData data = cricketDataMap.get(crickedId);
        if(data == null){
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketConfig cricketConfig = CricketMgr.getConfig().getCricketConfig(crickedId);
        if(cricketConfig == null){
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        if (GameConfig.CRICKET_EQUIP_CRICKET_QUALITY_LIMIT > cricketConfig.getQuality()) {
            return GameErrorCode.E_CRICKET_CAN_NOT_EQUIP;
        }
        UserPatrons userPatrons = player.getModule(PatronsModule.class).getUserPatrons(patronsId);
        if (userPatrons == null) {
            return GameErrorCode.E_PATRONS_NO_FOUND;
        }
        if (!canMountCricket(crickedId, patronsId)) {
            return GameErrorCode.E_PATRONS_CAN_NOT_MOUNT_CRICKET_IN_ACTIVITY;
        }
        //是否允许装备
        if(!UnionPhaseWarMgr.canMountCricket(player, crickedId, patronsId)){
            return GameErrorCode.E_UNION_WAR_ACTIVITY_CRICKET_IN_WAR_NOT_MOUNT;
        }
        //超过免费次数 需要消耗
        String cost = "";
        if (data.getEquipTimes() >= GameConfig.CRICKET_DEFAULT_EQUIP_TIMES) {
            //装备消耗
            int ingots = CricketMgr.getCricketEquipCost(data.getEquipBuyTimes());
            Property costProperty = new Property(GameConfig.GAME_MONEY_INGOTS, BigInteger.valueOf(ingots));
            if (!player.getModule(CurrencyModule.class).removeCurrency(costProperty,
                    eLogMoneyType.Cricket, eLogMoneyType.CricketEquip)) {
                return GameErrorCode.E_BAG_INGOTS_NO_ENOUGH;
            }
            data.setEquipBuyTimes(data.getEquipBuyTimes() + 1);
            cost = PropertyHelper.parsePropertyToString(costProperty);
        }
        //如果门客装备了鱼,先把装备的卸下
        disEquipCricket(patronsId);
        //如果鱼被装备了,先卸下来
        disEquipCricket(data.getEquipPatronsId());
        data.setEquipPatronsId(patronsId);
        data.setEquipTimes(data.getEquipTimes() + 1);
        syncSingleCricket(data);
        syncPatrons(data.getEquipPatronsId());

        AutoLogMgr.add(new LogCricketEquip(
                player.getUserId(),
                patronsId,
                crickedId,
                true,
                cost
        ));

        //商会战活动
        UnionPhaseWarMgr.equipCricket(player, crickedId, patronsId);
        player.getModule(RankUnionWarModule.class).equipVehicleOrFish(patronsId);
        return 0;
    }

    private Map<Integer,Map<Integer,Integer>> getKillUpInfoMap(int skillId){
        //升级信息
        Map<Integer,Map<Integer,Integer>> skillUpInfoMap = new ConcurrentHashMap<>();
        String str = "";
        if(skillId == 632601){
            str = GameConfig.CRICKET_PARTON_EQUIP_SKILL_PARAM_632601;
        }else if(skillId == 632602){
            str = GameConfig.CRICKET_PARTON_EQUIP_SKILL_PARAM_632602;
        }
        if(StringUtils.isNullOrEmpty(str)){
            return null;
        }
        List<String> tempStrList = StringUtils.stringToStringList(str,"\\|");
        for(String infoStr : tempStrList){
            List<Integer> infoList = StringUtils.stringToIntegerList(infoStr,";");
            Map<Integer,Integer> infoMap = new ConcurrentHashMap<>();
            infoMap.put(infoList.get(2),infoList.get(0));
            skillUpInfoMap.put(infoList.get(1),infoMap);
        }
        return skillUpInfoMap;
    }

    public int skillUp(int crickedId, int skillId, int goodsIndex){
        CricketData data = cricketDataMap.get(crickedId);
        if(data == null){
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketEquipSkill cricketEquipSkill = data.getEquipSkill(skillId);
        if (cricketEquipSkill == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        int oldSkillLv = cricketEquipSkill.getLv();
        int title = data.getTitle();
        int littleTitle = data.getLittleTitle();
        Map<Integer,Map<Integer,Integer>> infoMap = getKillUpInfoMap(skillId);
        if(infoMap != null){
            int maxLevel = 0;
            for(int checkTitle : infoMap.keySet()){
                if(title >= checkTitle){
                    for(int checkLittleTitle : infoMap.get(checkTitle).keySet()){
                        if(littleTitle >= checkLittleTitle && infoMap.get(checkTitle).get(checkLittleTitle) > maxLevel){
                            maxLevel = infoMap.get(checkTitle).get(checkLittleTitle);
                        }
                    }
                }
            }
            if(maxLevel != 0){
                if(oldSkillLv + 1 > maxLevel){
                    return GameErrorCode.E_CRICKET_PARTON_NORMAL_SKILL_UP_UNLOCK;
                }
            }
        }
        SkillInfo skillInfo = SkillMgr.getSkillInfo(cricketEquipSkill.getSkillId());
        if (skillInfo == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }

        if (skillInfo.getMaxLevel() <= cricketEquipSkill.getLv()) {
            return GameErrorCode.E_UPGRADE_LEVEL_MAX;
        }
        SkillUpgradeInfo skillUpgradeInfo = SkillMgr.getSkillUpgradeInfo(skillInfo.getUpgradeType(goodsIndex), oldSkillLv);
        if (skillUpgradeInfo == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        String costStr = skillInfo.getConsumeGoodsId().get(goodsIndex) + "=" + skillUpgradeInfo.getConsumeCount();
        if(!player.getModule(CurrencyModule.class).currencyIsEnough(PropertyHelper.parseStringToProperty(costStr))){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        if(!player.getModule(CurrencyModule.class).removeCurrency(PropertyHelper.parseStringToProperty(costStr),eLogMoneyType.Cricket,eLogMoneyType.CricketSkillUp)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        cricketEquipSkill.setLv(oldSkillLv + 1);

        //装备在门客身上加门客资质
        if(data.getEquipPatronsId() != 0){
            syncPatrons(data.getEquipPatronsId());
        }
        CricketProto.CricketSkillUpRespMsg.Builder respMsg = CricketProto.CricketSkillUpRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setCricketId(data.getCricketId());
        respMsg.setSkillId(skillId);
        respMsg.setLv(cricketEquipSkill.getLv());
        player.sendPacket(ClientProtocol.U_CRICKET_SKILL_UP, respMsg);
        return 0;
    }

    /**
     * 蛐蛐技能等级回收,退还第一种物品（index = 0）
     * @param crickedId 蛐蛐id
     * @param skillId 技能id
     * @return int
     */
    public int skillRecycle(int crickedId, int skillId) {
        //判断用户是否24小时内已经操作过
        if (!this.checkDoSkillRecycleFlag()) {
            return GameErrorCode.E_CRICKET_SKILL_RECYCLE_COOLING_TIME;
        }
        //蛐蛐信息
        CricketData data = cricketDataMap.get(crickedId);
        if(data == null){
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        //蛐蛐技能信息
        CricketEquipSkill cricketEquipSkill = data.getEquipSkill(skillId);
        if (cricketEquipSkill == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        //技能配置信息
        SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
        if (skillInfo == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        //默认退还第一种物品
        int goodsIndex = 0;
        //返还的物品id
        int consumeGoodId = 0;
        if(null != skillInfo.getConsumeGoodsId()) {
            for (int i = 0; i < skillInfo.getConsumeGoodsId().size(); i++) {
                int goodsId = skillInfo.getConsumeGoodsId().get(i);
                if (goodsId == GameConfig.CRICKET_SKILL_RECYCLE_RETURN_GOODS) {
                    goodsIndex = i;
                    consumeGoodId = goodsId;
                    break;
                }
            }
        }
        if(0 == consumeGoodId){
            return GameErrorCode.E_CRICKET_SKILL_RECYCLE_NOT_GOODS;
        }
        //技能升级类型
        int upgradeType = skillInfo.getAllUpgradeType().get(goodsIndex);
        //根据当前技能等级，计算需要退还多少数量
        int recycleNum = SkillMgr.getSkillConsumeByLevel(upgradeType, cricketEquipSkill.getLv());
        if (recycleNum <= 0) {
            return GameErrorCode.E_CRICKET_SKILL_RECYCLE_NOT_GOODS;
        }
        //变更蛐蛐技能等级为1
        cricketEquipSkill.setLv(1);
        //退还物品
        String recycleStr = consumeGoodId + "=" + recycleNum;
        player.getModule(CurrencyModule.class).addCurrency(PropertyHelper.parseStringToProperty(recycleStr), eLogMoneyType.Cricket, eLogMoneyType.CricketSkillLevelRecycleAddGoods);
        //存储操作回收时间
        long skillRecycleTime = System.currentTimeMillis();
        userCricketData.setSkillRecycleTime(skillRecycleTime);
        //装备在门客身上,更新门客
        if(data.getEquipPatronsId() != 0){
            syncPatrons(data.getEquipPatronsId());
        }
        //推送客户端
        CricketProto.CricketSkillRecycleRespMsg.Builder respMsg = CricketProto.CricketSkillRecycleRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setSkillRecycleTime(skillRecycleTime);
        respMsg.setReturnProp(recycleStr);
        respMsg.setLevel(cricketEquipSkill.getLv());
        player.sendPacket(ClientProtocol.U_CRICKET_SKILL_RECYCLE, respMsg);
        return 0;
    }

    /**
     * 操作前检查，1.判断用户是否24小时内已经操作过
     * @return
     */
    private boolean checkDoSkillRecycleFlag() {
        long timeNum = GameConfig.CRICKET_SKILL_RECYCLE_CD_TIME * DateHelper.HOUR_MILLIONS;
        if(System.currentTimeMillis() - userCricketData.getSkillRecycleTime() >= timeNum) {
            return true;
        }
        return false;
    }

    private void syncSingleCricket(CricketData cricketData) {
        syncCricketData(Collections.singletonList(cricketData));
    }

    private boolean canMountCricket(int cricketId, int patronsId) {
        PatronsCricketBindingData bindingData = patronsCricketBindingDataMap.get(cricketId);
        if (bindingData == null) {
            return true;
        }
        if (bindingData.getPatronsId() == patronsId || bindingData.getPatronsId() == 0) {
            return true;
        }
        if (DateHelper.getCurrentSecond() >= bindingData.getSystemEndTime()) {
            bindingData.setPatronsId(0);
            return true;
        }
        return false;
    }

    private void disEquipCricket(int patronsId){
        if(patronsId == 0){
            return;
        }
        CricketData userCricketByPatrons = CricketMgr.getUserCricketByPatrons(patronsId,cricketDataMap);
        if(userCricketByPatrons != null){
            userCricketByPatrons.setEquipPatronsId(0);
            syncCricketData(userCricketByPatrons);
            syncPatrons(patronsId);

            //商会战活动
            UnionPhaseWarMgr.dismountCricket(player, patronsId, userCricketByPatrons.getCricketId());
        }
        AutoLogMgr.add(new LogCricketEquip(
                player.getUserId(),
                patronsId,
                0,
                false,
                ""
        ));

    }

    private void syncPatrons(int patronsId) {
        //同步门客
        PatronsModule module = player.getModule(PatronsModule.class);
        UserPatrons userPatrons = module.getUserPatrons(patronsId);
        if (userPatrons != null) {
            module.onPatronsChange(userPatrons);
        }
    }

    //历史的蛐蛐更新一次性加缘分值
    private void addCricketFateValue(){
        if(player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.QuquWushuangFateSendAndDefense) == 0){
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.QuquWushuangFateSendAndDefense,1);
            Property historyProp = new Property();
            for(CricketBookData data : bookDataMap.values()){
                CricketConfig cricketConfig = CricketMgr.getConfig().getCricketConfig(data.getCricketId());
                if(cricketConfig != null){
                    Property addProp = PropertyHelper.parseStringToProperty(cricketConfig.getRelationPoint());
                    addProp.rideProperty(data.getTotalCount());
                    historyProp.addProperty(addProp);
                }
            }
            if(!historyProp.isNothing()){
                player.getModule(CurrencyModule.class).addCurrency(historyProp,eLogMoneyType.Cricket,eLogMoneyType.CricketHistoryFate);
            }
            changeDefense();
        }
    }

    //大到小排序
    class CricketAbilitySort implements Comparator<CricketData> {
        @Override
        public int compare(CricketData o1, CricketData o2) {
            if (o1.getCricketProperty().getAbility() == o2.getCricketProperty().getAbility()) {
                return 0;
            }
            if (o1.getCricketProperty().getAbility() > o2.getCricketProperty().getAbility()) {
                return -1;
            }
            return 1;
        }
    }


    //防守蛐蛐只能是配置的前多少个战力的蛐蛐，更新后统一修改玩家数据一次
    private void changeDefense(){
        if(GameConfig.CRICKET_FIGHT_DEF_FIT_NUM > GameConfig.CRICKET_FIGHT_DEF_PICK_NUM){
            //配置错了，选的小于必须上的
            return;
        }
        //可以前多少蛐蛐选
        int numPickUp = GameConfig.CRICKET_FIGHT_DEF_PICK_NUM;
        UserCricketData data = getUserCricketData();
        if (data == null) {
            return;
        }
        ArrayList<Integer> defList = data.getCricketMatchData().getDefenseList();
        if (defList.size() < GameConfig.CRICKET_FIGHT_DEF_FIT_NUM) {
            return;
        }
        //还没大于能选的上限，上什么都可以
        Map<Integer, CricketData> cMap = getCricketDataMap();
        Map<Integer,CricketData> pMap = new ConcurrentHashMap<>();
        List<CricketData> cList = new ArrayList<>(cMap.values());
        cList.sort(new CricketAbilitySort());
        for(int i = 0;i < cList.size(); i++){
            pMap.put(cList.get(i).getCricketId(),cList.get(i));
            if(pMap.size() >= numPickUp){
                break;
            }
        }
        List<Integer> tempRemoveIdList = new ArrayList<>();
        for(int cricketId : defList){
            if(pMap.containsKey(cricketId)){
                pMap.remove(cricketId);
            }else{
                tempRemoveIdList.add(cricketId);
            }
        }
        if(tempRemoveIdList.size() > 0){
            log.warn("{}玩家移除{}蛐蛐",getUserId(),tempRemoveIdList);
        }
        for(Integer removeCId : tempRemoveIdList){
            defList.remove(removeCId);
        }
        List<CricketData> sortList = new ArrayList<>(pMap.values());
        sortList.sort(new CricketAbilitySort());
        for(CricketData cricketData : sortList){
            if (defList.size() < GameConfig.CRICKET_FIGHT_DEF_FIT_NUM) {
                defList.add(cricketData.getCricketId());
            }else{
                break;
            }
        }
        if(tempRemoveIdList.size() > 0){
            data.setUpdateOption();
            syncData();
        }
    }

    /**
     * 重新计算蛐蛐属性
     */
    private void reCheckCricketData() {
        for (int cricketId : cricketDataMap.keySet()) {
            // 刷新一下蛐蛐数据
            CricketData cricketData = getCricketData(cricketId);
            if (cricketData == null) {
                continue;
            }
            // 计算属性
            calcProperty(cricketData);
            // 检测技能
            checkCricketSkill(cricketData);
        }
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userCricketData != null) {
            if (userCricketData.isInsertOption()) {
                UserCricketBussiness.addUserCricket(userCricketData);
            } else if (userCricketData.isUpdateOption()) {
                UserCricketBussiness.updateUserCricket(userCricketData);
            }
        }
        for (CricketData cricketData : cricketDataMap.values()) {
            if (cricketData.isInsertOption()) {
                UserCricketBussiness.addCricket(cricketData);
            } else if (cricketData.isUpdateOption()) {
                UserCricketBussiness.updateCricket(cricketData);
            }
            for(CricketEquipSkill skillData : cricketData.getEquipSkillList()){
                if(skillData.isInsertOption()){
                    UserCricketBussiness.addCricketEquipSkill(skillData);
                }else if(skillData.isUpdateOption()){
                    UserCricketBussiness.updateCricketEquipSkill(skillData);
                }
            }
        }
        for (CricketBookData bookData : bookDataMap.values()) {
            if (bookData.isInsertOption()) {
                UserCricketBussiness.addCricketBook(bookData);
            } else if (bookData.isUpdateOption()) {
                UserCricketBussiness.updateCricketBook(bookData);
            }
        }
        if (patronsCricketBindingDataMap != null) {
            for (PatronsCricketBindingData data : new ArrayList<>(patronsCricketBindingDataMap.values())) {
                if (data.isInsertOption()) {
                    UserCricketBussiness.addCricketBind(data);
                } else if (data.isUpdateOption()) {
                    UserCricketBussiness.updateCricketBind(data);
                }
            }
        }

        return true;
    }

    public void checkAndReset() {
        long zeroTime = DateHelper.getTodayZeroTime();
        long attrValue = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.QuquWushuangFateSendAndDefense);
        if(attrValue != 0 && attrValue != zeroTime){
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.QuquWushuangFateSendAndDefense,zeroTime);
            List<CricketData> syncList = new ArrayList<>();
            if (null != cricketDataMap) {
                for (CricketData cricketData : cricketDataMap.values()) {
                    if (cricketData.getEquipTimes() != 0 || cricketData.getEquipBuyTimes() != 0) {
                        syncList.add(cricketData);
                    }
                    cricketData.setEquipTimes(0);
                    cricketData.setEquipBuyTimes(0);
                }
            }
            if (syncList.size() > 0) {
                syncCricketData(syncList);
            }
        }

        //重置绑定次数的
        int hours = DateHelper.getHours();
        long now = System.currentTimeMillis() / 1000;
        long needResetTime = DateHelper.getDateByHours(22).getTime() / 1000;
        boolean needSync = false;
        for (PatronsCricketBindingData data : new ArrayList<>(patronsCricketBindingDataMap.values())) {
            long lastResetTime = data.getLastUpdateTime() / 1000;
            if (DateHelper.isSameDay(now, lastResetTime)) {
                //如果是同一天 只有过了22点才行
                if (hours < 22) {
                    continue;
                }
                if (lastResetTime >= needResetTime) {
                    continue;
                }
            }
            if (now < data.getSystemEndTime()) {
                continue;
            }
            data.setLastUpdateTime(now * 1000);
            data.setPatronsId(0);
            data.getActivityIdList().clear();
            needSync = true;
        }
        if (needSync) {
            syncPatronsBindMsg(new ArrayList<>(patronsCricketBindingDataMap.values()));
        }
        List<PatronsCricketBindingData> syncList = new ArrayList<>();
        for (PatronsCricketBindingData data : new ArrayList<>(patronsCricketBindingDataMap.values())) {
            List<Integer> activityIdList = data.getActivityIdList();
            if (activityIdList != null) {
                for (Integer activityId : activityIdList) {
                    ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
                    if (activityInfo == null) {
                        activityInfo = StrongholdActivityMgr.getInTimeActivityInfo(activityId);
                    }
                    if (activityInfo == null) {
                        data.removeActivityId(activityId);
                        needSync = true;
                        break;
                    }
                }
            }
            if (needSync) {
                syncList.add(data);
            }
        }
        if (syncList.size() > 0) {
            syncPatronsBindMsg(syncList);
        }
    }

    /**
     * 初始化系统
     */
    public void initSystem() {
        // 初始化用户信息
        initUserData();
        if (!player.getModule(BadgeModule.class).getUserBadgeMap().containsKey(eBadgeType.Cricket.getValue())) {
            updateBadge();
        }
        // 数据同步
        syncData();
    }

    public void syncData() {
        // 同步用户信息
        syncUserData();
        // 同步道具信息
        syncCricketItemData();
        // 同步图鉴信息
        syncCricketBookData();
    }

    public void syncConfig() {
        CricketProto.CricketConfigSyncMsg.Builder syncMsg = CricketProto.CricketConfigSyncMsg.newBuilder();
        for (CricketCourtConfig courtConfig : CricketMgr.getConfig().getCricketCourtConfigMap().values()) {
            CricketProto.CricketCourtConfigMsg.Builder temp = CricketPb.parseCricketCourtConfigMsg(courtConfig);
            if (temp != null) {
                syncMsg.addCourtConfig(temp);
            }
        }
        player.sendPacket(Protocol.U_CRICKET_CONFIG_SYNC, syncMsg);
    }

    /**
     * 初始化用户数据
     */
    private synchronized void initUserData() {
        if (userCricketData != null) {
            return;
        }
        userCricketData = new UserCricketData();
        userCricketData.setUserId(player.getUserId());
        userCricketData.setCatchEventTimes(0);
        userCricketData.setCricketIdList(new ArrayList<>());
        userCricketData.setBadgeLevel(1);
        userCricketData.setCricketScore(0);
        userCricketData.setScenceDataMap(new ConcurrentHashMap<>());
        userCricketData.setScenceId(CricketMgr.getFirstScenceId());
        userCricketData.setItems(new Property());
        userCricketData.setTotalCatchTimes(0);
        userCricketData.setDrawPieceCount(0);
        userCricketData.setDrawLevel(0);
        userCricketData.setDrawRewardLevel(0);
        userCricketData.setDrawReward(new Property());
        userCricketData.setGuideBit(0);
        userCricketData.setTotalOneCatchTimes(0);
        userCricketData.setTotalTenCatchTimes(0);
        userCricketData.setInsertOption();
        // 初始化当前场景信息
        initScenceData();
        // 更新勋章
        updateBadge();
        // 刷新事件列表
        refreshEventList();
    }

    /**
     * 初始化场景信息
     */
    private void initScenceData() {
        if (userCricketData == null) {
            return;
        }
        initScenceData(userCricketData.getScenceId());
    }

    /**
     * 初始化场景信息
     *
     * @param scenceId 场景信息
     */
    private CricketScenceData initScenceData(int scenceId) {
        if (userCricketData == null) {
            return null;
        }
        CricketScenceData cricketScenceData = new CricketScenceData();
        cricketScenceData.setScenceId(scenceId);
        cricketScenceData.setCatchTimes(0);
        cricketScenceData.setUpCount(0);
        cricketScenceData.setUpCricketId(0);
        userCricketData.getScenceDataMap().put(scenceId, cricketScenceData);
        userCricketData.setUpdateOption();
        return cricketScenceData;
    }

    private void syncUserData() {
        UserCricketData userCricketData1 = this.getUserCricketData();
        if (userCricketData1 == null) {
            return;
        }
        CricketProto.UserCricketDataSyncMsg.Builder builder = CricketProto.UserCricketDataSyncMsg.newBuilder();
        builder.setUserData(CricketPb.parseUserDataTemp(userCricketData1, cricketDataMap));
        player.sendPacket(ClientProtocol.U_CRICKET_USER_DATA_SYNC, builder);
    }

    /**
     * 同步道具信息
     */
    private void syncCricketItemData() {
        if (userCricketData == null) {
            return;
        }
        CricketProto.CricketItemDataSyncMsg.Builder builder = CricketProto.CricketItemDataSyncMsg.newBuilder();
        builder.addAllItem(CricketPb.parseCricketItemMsgList(userCricketData.getItems()));
        player.sendPacket(ClientProtocol.U_CRICKET_ITEM_DATA_SYNC, builder);
    }

    /**
     * 同步图鉴信息
     */
    private void syncCricketBookData() {
        if (userCricketData == null) {
            return;
        }
        CricketProto.CricketBookDataSyncMsg.Builder builder = CricketProto.CricketBookDataSyncMsg.newBuilder();
        for (CricketBookData bookData : bookDataMap.values()) {
            builder.addBook(CricketPb.parseCricketBookTempMsg(bookData));
        }
        player.sendPacket(ClientProtocol.U_CRICKET_BOOK_DATA_SYNC, builder);
    }


    /**
     * 选择特殊事件的蛐蛐奖励
     */
    public int chooseEventReward(int cricketId) {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        if (userCricketData.getCatchEventTimes() < GameConfig.CRICKET_CATCH_EVENT_CD) {
            // 次数不足
            return GameErrorCode.E_CRICKET_SPECIAL_EVENT_TIMES_NO_ENOUGH;
        }
        if (!userCricketData.getCricketIdList().contains(cricketId)) {
            return GameErrorCode.E_CRICKET_PARAM_ERROR;
        }
        // 修复bug 抽到圣兽换一只
//        List<Integer> shengshouList = StringUtils.stringToIntegerList(GameConfig.CRICKET_CHANGE_GET, "\\|");
//        if (shengshouList.contains(cricketId)) {
//            CricketConfigManager config = CricketMgr.getConfig();
//            CricketConfig cricketConfig = config.randomGetCricketByQuality(eCricketQualityType.Red.getValue());
//            if (cricketConfig != null) {
//                cricketId = cricketConfig.getId();
//            }
//        }
        // 更新次数
        userCricketData.setCatchEventTimes(userCricketData.getCatchEventTimes() - GameConfig.CRICKET_CATCH_EVENT_CD);
        // 获得蛐蛐
        CricketData cricketData = addCricket(cricketId, BigInteger.ONE, eLogMoneyType.Cricket, eLogMoneyType.CricketChooseEventReward, true);
        // 刷新事件列表
        refreshEventList();
        CricketProto.ChooseEventRewardRespMsg.Builder respMsg = CricketProto.ChooseEventRewardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setCricketChange(CricketPb.parseCricketDataChange(cricketData));
        respMsg.setCatchEventTimes(userCricketData.getCatchEventTimes());
        respMsg.addAllCricketIdList(userCricketData.getCricketIdList());
        respMsg.setCricketScore(getCricketScoreAdd(cricketData));
        player.sendPacket(ClientProtocol.U_CRICKET_CHOOSE_EVENT_REWARD, respMsg);
        return 0;
    }

    /**
     * 返回增加的积分
     */
    public int getCricketScoreAdd(CricketData cricketData) {
        if (cricketData == null) {
            return 0;
        }
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return 0;
        }
        int quality = CricketMgr.getCricketQuality(cricketData.getCricketId());
        List<Integer> eventScoreList = StringUtils.stringToIntegerList(GameConfig.CRICKET_CATCH_EVENT_SCORE, "\\|");
        int qualityIdx = Math.max(0, quality - 1);
        return eventScoreList.get(Math.min(eventScoreList.size() - 1, qualityIdx));
    }

    private void refreshEventList() {
        if (userCricketData == null) {
            return;
        }
        // 刷新列表
        List<Integer> list = CricketMgr.getEventCricketList();
        // 打乱一下
        Collections.shuffle(list);
        // 更新选择列表
        userCricketData.setCricketIdList(list);
    }

    /**
     * 选择心愿蛐蛐
     *
     * @param cricketId 蛐蛐id
     */
    public int chooseUp(int cricketId) {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketConfig cricketConfig = config.getCricketConfig(cricketId);
        if (config == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketScenceConfig cricketScenceConfig = config.getCricketScenceConfig(userCricketData.getScenceId());
        if (cricketScenceConfig == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        List<Integer> wishPool = StringUtils.stringToIntegerList(cricketScenceConfig.getWishPool(), "\\|");
        // 只能选择心愿池的蛐蛐
        if (!wishPool.contains(cricketId)) {
            return GameErrorCode.E_CRICKET_CHOOSE_UP_LIMIT;
        }
        // 当前场景信息
        CricketScenceData cricketScenceData = getCricketScenceData(userCricketData.getScenceId());
        // 判断是否锁定,当前场景的再次选择不做拦截
        for (CricketScenceData scenceData : userCricketData.getScenceDataMap().values()) {
            if (scenceData.getScenceId() != cricketScenceData.getScenceId() && scenceData.getUpCricketId() == cricketId) {
                return GameErrorCode.E_CRICKET_CHOOSE_UP_LOCK;
            }
        }
        if (cricketScenceData.getUpCount() >= GameConfig.CRICKET_CATCH_PRO_UP_TIMES) {
            return GameErrorCode.E_CRICKET_CHOOSE_UP_NO_ENOUGH;
        }
        cricketScenceData.setUpCricketId(cricketId);
        userCricketData.getScenceDataMap().put(userCricketData.getScenceId(), cricketScenceData);
        userCricketData.setUpdateOption();
        CricketProto.CricketChooseUpRespMsg.Builder respMsg = CricketProto.CricketChooseUpRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setScence(CricketPb.parseCricketScenceTemp(cricketScenceData));
        player.sendPacket(ClientProtocol.U_CRICKET_CHOOSE_UP, respMsg);
        AutoLogMgr.add(new LogCricketChooseUp(
                player.getUserId(),
                cricketId
        ));
        return 0;
    }

    /**
     * 获取当前蛐蛐下一阶的信息预览
     *
     * @param cricketId 蛐蛐id
     */
    public int getCricketUpNextInfo(int cricketId) {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketConfig cricketConfig = config.getCricketConfig(cricketId);
        if (cricketConfig == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketData cricketData = getCricketData(cricketId);
        if (cricketData == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketUpConfig nextCricketUpConfig = CricketMgr.getNextCricketUpConfig(cricketId, cricketData.getTitle(), cricketData.getLittleTitle());
        if (nextCricketUpConfig == null) {
            return GameErrorCode.E_CRICKET_UPGRADE_LIMIT;
        }
        // 预览数据不改变当前蛐蛐数据，克隆一份
        CricketData clone = cricketData.clone();
        clone.setTitle(nextCricketUpConfig.getTitle());
        clone.setLittleTitle(nextCricketUpConfig.getLittleTitle());
        // 计算属性
        calcProperty(clone);
        CricketProto.CricketUpNextInfoRespMsg.Builder respMsg = CricketProto.CricketUpNextInfoRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setCricket(CricketPb.parseCricketTemp(clone));
        player.sendPacket(ClientProtocol.U_CRICKET_UP_NEXT_INFO, respMsg);
        return 0;
    }

    /**
     * 领取绘卷奖励
     */
    public int getDrawLevelReward() {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        Property drawReward = userCricketData.getDrawReward();
        if (drawReward.isNothing()) {
            return GameErrorCode.E_CRICKET_DRAW_NO_REWARD;
        }
        // 领奖
        player.getModule(CurrencyModule.class).addCurrency(drawReward, eLogMoneyType.Cricket, eLogMoneyType.CricketGetDrawLevelReward);
        // 清空可领奖的奖励
        userCricketData.setDrawReward(new Property());
        // 记录下当前领奖的等级
        userCricketData.setDrawRewardLevel(userCricketData.getDrawLevel());
        CricketProto.CricketGetDrawLevelRewardRespMsg.Builder respMsg = CricketProto.CricketGetDrawLevelRewardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(drawReward));
        player.sendPacket(ClientProtocol.U_CRICKET_GET_DRAW_LEVEL_REWARD, respMsg);
        // 同步用户数据
        syncUserData();
        return 0;
    }


    public int finishGuide(int flag) {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        if ((userCricketData.getGuideBit() >> (flag - 1) & 1) == 1) {
            // 已完成引导
            return GameErrorCode.E_CRICKET_ALREADY_FINISH_GUIDE;
        }
        CricketProto.CricketFinishGuideRespMsg.Builder respMsg = CricketProto.CricketFinishGuideRespMsg.newBuilder();
        respMsg.setRet(0);
        String reward = "";
        // 领奖
        if (flag == 1) {
            reward = GameConfig.CRICKET_NEW_REWARD;
        } else if (flag == 6) {
            reward = GameConfig.CRICKET_NEW_REWARD_END;
        }
        // 记录引导
        userCricketData.setGuideBit(userCricketData.getGuideBit() | (1 << (flag - 1)));
        if (!StringUtils.isNullOrEmpty(reward)) {
            player.getModule(CurrencyModule.class).addCurrency(PropertyHelper.parseStringToProperty(reward), eLogMoneyType.Cricket, eLogMoneyType.CricketFinishGuideReward);
            respMsg.setReward(reward);
        }
        respMsg.setGuideBit(userCricketData.getGuideBit());
        player.sendPacket(ClientProtocol.U_CRICKET_FINISH_GUIDE, respMsg);
        return 0;
    }


    public int showCourtRank() {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        userCricketData.setShowCourtRank(true);
        CricketProto.CricketShowCourtRankRespMsg.Builder respMsg = CricketProto.CricketShowCourtRankRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setShowCourtRank(userCricketData.isShowCourtRank());
        player.sendPacket(ClientProtocol.U_CRICKET_SHOW_COURT_RANK, respMsg);
        return 0;
    }

    /**
     * 获取当前场景的场景信息
     */
    public CricketScenceData getCricketScenceData(int scenceId) {
        if (!userCricketData.getScenceDataMap().containsKey(scenceId)) {
            // 初始化场景信息
            return initScenceData(scenceId);
        } else {
            return userCricketData.getScenceDataMap().get(scenceId);
        }
    }


    /**
     * 捕捉蛐蛐
     *
     * @param type 捕捉类型 1:单次 2:十次
     */
    public int catchCricket(int type) {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        // 捕捉次数
        int times;
        if (type == 1) {
            times = 1;
        } else if (type == 2) {
            times = 10;
            // 判断10连抽是否解锁
            if (userCricketData.getTotalCatchTimes() < GameConfig.CRICKET_CATCH_TEN_OPEN) {
                return GameErrorCode.E_CRICKET_CATCH_TEN_NOT_OPEN;
            }
        } else if (type == 3) {
            times = 100;
            // 判断100连抽是否解锁
            if (userCricketData.getBadgeLevel() < GameConfig.CRICKET_CATCH_HUNDRED_OPEN) {
                return GameErrorCode.E_CRICKET_CATCH_HUNDRED_NOT_OPEN;
            }
        } else {
            return GameErrorCode.E_CRICKET_PARAM_ERROR;
        }
        // 消耗道具
        int catchItemId = GameConfig.CRICKET_CATCH_ITEM_ID;
        CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
        //触发现金礼包
        if(!currencyModule.currencyIsEnough(new Property(catchItemId, 10))){
            player.notifyListener(eGamePlayerEventType.RechargeCricketTrain.getValue(), 0);
        }
        //6.1新增 如果道具不足百连 有多少用多少
        if (type == 3){
            //这里的time是100 应该
            if (!currencyModule.currencyIsEnough(new Property(catchItemId, times))) {
                //拿出背包
                UserBagItem userBagItem = player.getModule(BagModule.class).getUserBagItem(catchItemId);
                //如果背包有 并且数量大于0
                if (userBagItem != null && userBagItem.getNum() > 0) {
                    times = (int) userBagItem.getNum();
                } else {
                    return GameErrorCode.E_CRICKET_CATCH_ITEM_NO_ENOUGH;
                }
            }
        }
        if (!currencyModule.removeCurrency(new Property(catchItemId, times), eLogMoneyType.Cricket, eLogMoneyType.CricketCatchCost)) {
            return GameErrorCode.E_CRICKET_CATCH_ITEM_NO_ENOUGH;
        }
        // 获取当前场景信息
        int scenceId = userCricketData.getScenceId();
        CricketScenceData cricketScenceData = getCricketScenceData(scenceId);
        // 先随机品质
        List<CricketData> cricketDataList = new ArrayList<>();
        // 蛐蛐积分
        long totalCricketScore = 0;
        List<Integer> drawCricketIdList = new ArrayList<>();
        for (int i = 0; i < times; i++) {
            int quality = CricketMgr.getCatchQualityByWeight(scenceId);
            if (quality == 0) {
                continue;
            }
            int cricketId = 0;
            // 抽中无双先抽心愿
            if (quality == eCricketQualityType.Red.getValue() && cricketScenceData.getUpCricketId() != 0 && cricketScenceData.getUpCount() < GameConfig.CRICKET_CATCH_PRO_UP_TIMES) {
                // 心愿蛐蛐概率提升权重值
                if (randomHelper.next(1000) < GameConfig.CRICKET_CATCH_PRO_UP_NUM) {
                    cricketId = cricketScenceData.getUpCricketId();
                }
            }
            if (cricketId == 0) {
                // 蛐蛐库随机
                List<String> matchLibrary = CricketMgr.matchLibraryWithQuality(scenceId, quality);
                // 抽蛐蛐
                cricketId = CricketMgr.drawCricketWithLibrary(matchLibrary);
            }
            if (cricketId == 0) {
                continue;
            }
            drawCricketIdList.add(cricketId);
        }
        // 首次单抽对结果进行处理，此处读表
        if (type == 1 && userCricketData.getTotalOneCatchTimes() == 0) {
            // 列表只有1个，直接清掉
            drawCricketIdList.clear();
            // 首抽蛐蛐
            drawCricketIdList.add(GameConfig.CRICKET_FIRST_DRAW);
        }
        // 首次10连对结果进行处理，此处写死处理
        if (type == 2 && userCricketData.getTotalTenCatchTimes() == 0) {
            checkFirstTenCatch(drawCricketIdList);
        }
        // 处理下up次数
        for (int cricketId : drawCricketIdList) {
            if (cricketId == cricketScenceData.getUpCricketId()) {
                cricketScenceData.setUpCount(cricketScenceData.getUpCount() + 1);
            }
        }
        // 打乱一下
        Collections.shuffle(drawCricketIdList);

        if (type == 3) {
            // 百连需要聚合一下
            Map<Integer, Integer> drawCricketIdMap = new HashMap<>();
            for (Integer cricketId : drawCricketIdList) {
                drawCricketIdMap.put(cricketId, drawCricketIdMap.getOrDefault(cricketId, 0) + 1);
            }
            for (Map.Entry<Integer, Integer> entry : drawCricketIdMap.entrySet()) {
                CricketData cricketData = addCricket(entry.getKey(), BigInteger.valueOf(entry.getValue()), eLogMoneyType.Cricket, eLogMoneyType.CricketCatchReward, false);
                cricketDataList.add(cricketData.clone());
                // 根据品质计算虫师积分
                totalCricketScore += calcCricketScore(catchItemId, entry.getKey(), entry.getValue());
            }
        } else {
            for (Integer cricketId : drawCricketIdList) {
                CricketData cricketData = addCricket(cricketId, BigInteger.ONE, eLogMoneyType.Cricket, eLogMoneyType.CricketCatchReward, false);
                cricketDataList.add(cricketData.clone());

                // 根据品质计算虫师积分
                totalCricketScore += calcCricketScore(catchItemId, cricketId, 1);
            }
        }
        // 增加积分
        player.getModule(CurrencyModule.class).addCurrency(new Property(GameConfig.CRICKET_EXP_ITEM_ID, totalCricketScore), eLogMoneyType.Cricket, eLogMoneyType.CricketCatchScore);
        userCricketData.setCatchEventTimes(userCricketData.getCatchEventTimes() + times);
        userCricketData.setTotalCatchTimes(userCricketData.getTotalCatchTimes() + times);
        if (type == 1) {
            // 单抽计数
            userCricketData.setTotalOneCatchTimes(userCricketData.getTotalOneCatchTimes() + 1);
        } else {
            // 十连抽计数
            userCricketData.setTotalTenCatchTimes(userCricketData.getTotalTenCatchTimes() + 1);
        }
        cricketScenceData.setCatchTimes(cricketScenceData.getCatchTimes() + times);
        userCricketData.getScenceDataMap().put(scenceId, cricketScenceData);
        // 检测是否切换场景
        changeScence();

        CricketProto.CatchCricketRespMsg.Builder respMsg = CricketProto.CatchCricketRespMsg.newBuilder();
        respMsg.setRet(0);
        for (CricketData cricketData : cricketDataList) {
            respMsg.addCricketChange(CricketPb.parseCricketDataChange(cricketData));
        }
        respMsg.setCricketScore(totalCricketScore);
        respMsg.setCatchEventTimes(userCricketData.getCatchEventTimes());
        // 当前场景信息
        respMsg.setScence(CricketPb.parseCricketScenceTemp(userCricketData.getScenceDataMap().get(userCricketData.getScenceId())));
        respMsg.setTotalCatchTimes(userCricketData.getTotalCatchTimes());
        player.sendPacket(ClientProtocol.U_CRICKET_CATCH_CRICKET, respMsg);

        userCricketData.setUpdateOption();

        // 同步用户信息
        syncData();

        CricketLog.trackCricketGet(player, cricketDataList, type, scenceId);
        return 0;
    }

    /**
     * 校验首次十连抽
     *
     * @param drawCricketIdList 十连抽奖励
     */
    private void checkFirstTenCatch(List<Integer> drawCricketIdList) {
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return;
        }
        Map<Integer, CricketConfig> cricketConfigMap = config.getCricketConfigMap();
        int scenceId = userCricketData.getScenceId();
        // 至少有1只橙色品质的蛐蛐，至多有1只无双品质的蛐蛐
        int orangeMinCountConfig = 1;
        int redMaxCountConfig = 1;
        Deque<Integer> orangeCricketQueue = new ArrayDeque<>();
        Deque<Integer> redCricketQueue = new ArrayDeque<>();
        for (Integer cricketId : drawCricketIdList) {
            CricketConfig cricketConfig = cricketConfigMap.get(cricketId);
            if (cricketConfig == null) {
                continue;
            }
            int quality = cricketConfig.getQuality();
            if (quality == eCricketQualityType.Orange.getValue()) {
                orangeCricketQueue.addLast(cricketId);
            }
            if (quality == eCricketQualityType.Red.getValue()) {
                redCricketQueue.addLast(cricketId);
            }

        }
        if (orangeCricketQueue.size() >= orangeMinCountConfig && redCricketQueue.size() <= redMaxCountConfig) {
            // 无需处理
            return;
        }

        // 检测红色品质
        while (redCricketQueue.size() > redMaxCountConfig) {
            // 随机一只
            int quality = CricketMgr.getCatchQualityByWeight(scenceId);
            if (quality == eCricketQualityType.Red.getValue()) {
                continue;
            }
            List<String> matchLibrary = CricketMgr.matchLibraryWithQuality(scenceId, quality);
            // 抽蛐蛐
            int cricketId = CricketMgr.drawCricketWithLibrary(matchLibrary);
            if (cricketId != 0) {
                int removeCricketId = redCricketQueue.removeLast();
                drawCricketIdList.remove(new Integer(removeCricketId));
                drawCricketIdList.add(cricketId);
                if (quality == eCricketQualityType.Orange.getValue()) {
                    orangeCricketQueue.addLast(cricketId);
                }
            }
        }

        while (orangeCricketQueue.size() < orangeMinCountConfig) {
            // 蛐蛐库随机
            List<String> matchLibrary = CricketMgr.matchLibraryWithQuality(scenceId, eCricketQualityType.Orange.getValue());
            // 抽蛐蛐
            int cricketId = CricketMgr.drawCricketWithLibrary(matchLibrary);
            if (cricketId != 0) {
                // 将最低级的奖励换成橙色奖励
                int minQualityCricketId = getMinQualityCricketId(drawCricketIdList);
                drawCricketIdList.remove(new Integer(minQualityCricketId));
                drawCricketIdList.add(cricketId);
                orangeCricketQueue.addLast(cricketId);
            }
        }
    }

    /**
     * 获取品质最低的一个蛐蛐
     *
     * @param drawCricketIdList
     * @return
     */
    private int getMinQualityCricketId(List<Integer> drawCricketIdList) {
        int res = 0;
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return res;
        }
        Map<Integer, CricketConfig> cricketConfigMap = config.getCricketConfigMap();
        int minQuality = Integer.MAX_VALUE;
        for (Integer cricketId : drawCricketIdList) {
            CricketConfig cricketConfig = cricketConfigMap.get(cricketId);
            if (cricketConfig == null) {
                continue;
            }
            int quality = cricketConfig.getQuality();
            if (quality <= minQuality) {
                res = cricketId;
                minQuality = quality;
            }
        }
        return res;
    }


    /**
     * 根据品质计算虫师积分
     */
    public int calcCricketScore(int catchItemId, int cricketId, int count) {
        // 获取虫师积分
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(catchItemId);
        if (goodsInfo == null) {
            return 0;
        }
        CricketConfig cricketConfig = CricketMgr.getConfig().getCricketConfigMap().get(cricketId);
        if (cricketConfig == null) {
            return 0;
        }
        int quality = cricketConfig.getQuality();
        if (goodsInfo.getParamList().size() < quality) {
            return 0;
        }
        return goodsInfo.getParamList().get(quality - 1).intValue() * count;
    }

    /**
     * 切换场景
     */
    public void changeScence() {
        if (userCricketData == null) {
            return;
        }
        // 获取当前场景的数据
        int scenceId = userCricketData.getScenceId();
        CricketScenceData curScenceData = getCricketScenceData(scenceId);
        if (curScenceData.getCatchTimes() >= GameConfig.CRICKET_CATCH_SCENCE_CHANGE_NUM) {
            // 超出的数量保留到下一张场景
            long moreTimes = curScenceData.getCatchTimes() - GameConfig.CRICKET_CATCH_SCENCE_CHANGE_NUM;
            // 切换场景
            int nextScenceId = CricketMgr.getNextScenceId(scenceId);
            CricketScenceData nextScenceData = getCricketScenceData(nextScenceId);
            // 已捕捉数量
            nextScenceData.setCatchTimes(moreTimes);
            // 次数重置
            nextScenceData.setUpCount(0);
            // 清空当前场景的次数
            curScenceData.setCatchTimes(0);
            userCricketData.getScenceDataMap().put(scenceId, curScenceData);
            userCricketData.getScenceDataMap().put(nextScenceId, nextScenceData);
            userCricketData.setScenceId(nextScenceId);
            userCricketData.setUpdateOption();
        }
    }

    /**
     * 刷新被动技能
     *
     * @param cricketId 蛐蛐id
     * @param index     技能索引
     */
    public int refreshSkill(int cricketId, int index) {
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        CricketData cricketData = getCricketData(cricketId);
        if (cricketData == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketData originCricketData = cricketData.clone();
        CricketSkill cricketSkill = cricketData.getSkillList().get(index);
        if (cricketSkill == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        int beforeSkillId = cricketSkill.getSkillId();
        // 判断消耗
        int quality = cricketData.getQuality();
        List<Integer> costList = StringUtils.stringToIntegerList(GameConfig.CRICKET_SKILL_GET_COST_NUM, "\\|");
        int qualityIdx = quality - 1;
        if (qualityIdx >= costList.size()) {
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        Property cost = new Property(GameConfig.CRICKET_SKILL_STAR_GET_ITEM_ID, costList.get(qualityIdx));
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.Cricket, eLogMoneyType.CricketRefreshSkillCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        // 更新技能
        // 排除当前的技能
        Set<Integer> exclusiveSkillIdSet = new HashSet<>();
        for (CricketSkill skill : cricketData.getSkillList()) {
            exclusiveSkillIdSet.add(skill.getSkillId());
        }

        int skillId = randomSkillId(exclusiveSkillIdSet, 0);
        if (skillId != 0) {
            replaceSkill(cricketData, skillId, index);
            // 技能变动
            skillChange();
        }
        // 蛐蛐数据变更
        cricketDataChange(cricketData);
        CricketProto.CricketRefreshSkillRespMsg.Builder respMsg = CricketProto.CricketRefreshSkillRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setCricketChange(CricketPb.parseCricketDataChange(cricketData));
        player.sendPacket(ClientProtocol.U_CRICKET_REFRESH_SKILL, respMsg);
        changeDefense();
        // 刷新技能日志
        AutoLogMgr.add(new LogCricketRefreshSkill(
                player.getUserId(),
                cricketId,
                cricketData.getQuality(),
                cricketData.getTitle(),
                cricketData.getLittleTitle(),
                PropertyHelper.parsePropertyToString(cost),
                beforeSkillId,
                skillId,
                originCricketData.getCricketProperty().getHp() + originCricketData.getAddProperty().getHp(),
                originCricketData.getCricketProperty().getAtk() + originCricketData.getAddProperty().getAtk(),
                originCricketData.getCricketProperty().getPower() + originCricketData.getAddProperty().getPower(),
                originCricketData.getCricketProperty().getAbility() + originCricketData.getAddProperty().getAbility(),
                cricketData.getCricketProperty().getHp() + cricketData.getAddProperty().getHp(),
                cricketData.getCricketProperty().getAtk() + cricketData.getAddProperty().getAtk(),
                cricketData.getCricketProperty().getPower() + cricketData.getAddProperty().getPower(),
                cricketData.getCricketProperty().getAbility() + cricketData.getAddProperty().getAbility()
        ));
        return 0;
    }

    /**
     * 获取被动技能星级
     */
    public int getPassiveSkillLevel() {
        int count = 0;
        for (CricketData cricketData : cricketDataMap.values()) {
            // 获取所有被动技能
            List<CricketSkill> allSkillList = new ArrayList<>();
            // 天生被动
            allSkillList.addAll(cricketData.getInitSkillList());
            // 被动技能
            allSkillList.addAll(cricketData.getSkillList());
            for (CricketSkill cricketSkill : allSkillList) {
                if (cricketSkill == null) {
                    continue;
                }
                int skillId = cricketSkill.getSkillId();
                // 获取星级
                SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
                if (skillInfo == null) {
                    continue;
                }
                count += skillInfo.getStars();
            }
        }
        return count;
    }

    /**
     * 添加绘卷碎片
     */
    public void addCricketDrawPieceItem(BigInteger count, eLogMoneyType master, eLogMoneyType son) {
        if (userCricketData == null) {
            return;
        }
        long beforeNum = userCricketData.getDrawPieceCount();
        userCricketData.setDrawPieceCount(userCricketData.getDrawPieceCount() + count.longValue());
        // 更新绘卷等级及奖励
        // 相关记录
        int oldLevel = userCricketData.getDrawLevel();
        // 升级消耗的数量
        long totalCostNum = 0;
        while (true) {
            // 当前绘卷等级
            int picLevel = userCricketData.getDrawLevel();
            // 获取下一级的绘卷等级配置
            String param = getDrawTaskParam(picLevel + 1);
            if ("".equals(param)) {
                // 做个容错,找不到配置跳出循环
                break;
            }
            String[] split = param.split("#");
            int costNum = Integer.parseInt(split[0]);
            // 足够升级
            if (userCricketData.getDrawPieceCount() >= costNum) {
                totalCostNum += costNum;
                // 扣除数量
                userCricketData.setDrawPieceCount(userCricketData.getDrawPieceCount() - costNum);
                // 升级
                userCricketData.setDrawLevel(picLevel + 1);
                // 累积奖励
                userCricketData.getDrawReward().addProperty(PropertyHelper.parseStringToProperty(split[1]));
            } else {
                // 跳出循环
                break;
            }
        }
        // 记录下绘卷相关日志
        AutoLogMgr.add(new LogCricketDrawLevel(
                player.getUserId(),
                beforeNum,
                count.longValue(),
                totalCostNum,
                userCricketData.getDrawPieceCount(),
                oldLevel,
                userCricketData.getDrawLevel(),
                master.getValue(),
                son.getValue()
        ));
        // 同步用户数据
        syncUserData();
    }

    /**
     * 获取指定等级的绘卷等级配置
     */
    public String getDrawTaskParam(int level) {
        List<String> paramList = StringUtils.stringToStringList(GameConfig.CRICKET_TASK_PIC, "\\|");
        int maxLevel = paramList.size();
        if (maxLevel == 0) {
            return "";
        }
        int levelIdx = (level - 1) % maxLevel;
        return paramList.get(levelIdx);
    }

    public void relationRewardGet(){
        CricketProto.CricketGetRelationMessageRespMsg.Builder respMsg = CricketProto.CricketGetRelationMessageRespMsg.newBuilder();
        CricketSystemConfig config = CricketMgr.getConfig();
        Property allReward = new Property();
        for(CricketData userCricketData : cricketDataMap.values()){
            if(userCricketData.getRewardNum() > 0){
                Property cricketReward = new Property();
                int cricketId = userCricketData.getCricketId();
                CricketConfig cricketConfig = config.getCricketConfig(cricketId);
                if (cricketConfig == null) {
                    log.error("cricket id：{} not found !!!!relationReward", cricketId);
                    continue;
                }
                CricketProto.CricketGetRelationTempMsg.Builder tempMsg = CricketProto.CricketGetRelationTempMsg.newBuilder();
                tempMsg.setCricketId(cricketId);
                tempMsg.setNum(userCricketData.getRewardNum());
                for(int i = 0; i < userCricketData.getRewardNum();i++){
                    cricketReward.addProperty(PropertyHelper.parseStringToProperty(cricketConfig.getRelationPoint()));
                }
                tempMsg.setReward(PropertyHelper.parsePropertyToString(cricketReward));
                allReward.addProperty(cricketReward);
                userCricketData.setRewardNum(0);
                respMsg.addCrickets(tempMsg);
            }
        }
        if(!allReward.isNothing()){
            player.getModule(CurrencyModule.class).addCurrency(allReward,eLogMoneyType.Cricket,eLogMoneyType.CricketRewardFate);
            syncUserData();
        }
        player.sendPacket(ClientProtocol.U_CRICKET_GET_REWARD_RELATION, respMsg);
    }
    /**
     * 获得蛐蛐
     *
     * @param getScore 是否获得虫师积分,用于投放    捕捉时这边不加积分，在捕捉逻辑加积分
     */
    public CricketData addCricket(int cricketId, BigInteger count, eLogMoneyType master, eLogMoneyType son, boolean getScore) {
        CricketSystemConfig config = CricketMgr.getConfig();
        CricketConfig cricketConfig = config.getCricketConfig(cricketId);
        if (cricketConfig == null) {
            log.error("cricket id：{} not found !!!!", cricketId);
            return null;
        }
        int num = count.intValue();
        if (num <= 0) {
            log.error("add cricket num error !!!!");
            return null;
        }
        CricketData cricketData = getCricketData(cricketId);

        boolean isInit = false;
        boolean isMax = false;
        // 蛐蛐数据变更
        CricketDataChange change = new CricketDataChange();
        if (cricketData == null) {
            // 不存在则初始化
            cricketData = initCricket(cricketId);
            isInit = true;
            num--;
        }
        if (num > 0) {
            // 检验材料是否可升至满级
            int moreCount = 0;

            int needCount = countOfMaxLevel(cricketData);
            int addCount;
            if (needCount >= num) {
                addCount = num;
            } else {
                // 满阶了
                isMax = true;
                // 多余的数量
                moreCount = num - needCount;
                addCount = needCount;
            }
            if (addCount > 0) {
                log.info("蛐蛐{},转换为材料:{}个", cricketId, addCount);
                // 转化为材料
                addItem(new Property(cricketId, addCount));
            }
            if (moreCount > 0) {
                // 转换数量
                String turnReward = CricketMgr.getCricketCatchMaxTurn(cricketId);
                Property property = PropertyHelper.parseStringToProperty(turnReward);
                for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
                    entry.setValue(entry.getValue().multiply(BigInteger.valueOf(moreCount)));
                }
                String reward = PropertyHelper.parsePropertyToString(property);
                change.setTurnReward(reward);
                log.info("蛐蛐{},超出数量：{},转换为{}", cricketId, moreCount, reward);
                // 多余的转换为积分
                player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Cricket, eLogMoneyType.CricketCatchMaxTurn);
            }
        }
        // 首次获得记录首次升到XX阶
        if (isInit) {
            player.notifyListener(eGamePlayerEventType.CricketUpTitle.getValue(), new CricketTiTleArgs(cricketId, cricketData.getTitle(), cricketData.getLittleTitle()));
        }
        change.setFirstGet(isInit);
        change.setGet(true);
        change.setMax(isMax);
        change.setCount(count.intValue());
        // 蛐蛐数据变动
        cricketData.setChange(change);
        cricketDataChange(cricketData);
        // 成就、任务
        player.notifyListener(eGamePlayerEventType.CricketGetTimes.getValue(), new CricketItemArgs(cricketId, count));
        // 更新图鉴
        addBook(cricketId, count.intValue());
        if(!StringUtils.isNullOrEmpty(cricketConfig.getRelationPoint()) && !"0".equals(cricketConfig.getRelationPoint())){
            //记录获得了多少蛐蛐没有领缘分值，进入庙里一起领取
            cricketData.setRewardNum(cricketData.getRewardNum() + count.intValue());
        }
        // 同步材料信息
        syncCricketItemData();
        // 同步图鉴信息
        syncCricketBookData();
        // 虫师积分
        long scoreAdd = 0;
        if (getScore) {
            scoreAdd = count.multiply(BigInteger.valueOf(getCricketScoreAdd(cricketData))).longValue();
            player.getModule(CurrencyModule.class).addCurrency(new Property(GameConfig.CRICKET_EXP_ITEM_ID, scoreAdd), eLogMoneyType.Cricket, eLogMoneyType.CricketGetScore);
            // 同步
            syncUserData();
        }
        // 记录日志
        AutoLogMgr.add(new LogCricketGet(
                player.getUserId(),
                cricketId,
                cricketData.getQuality(),
                cricketData.getTitle(),
                cricketData.getLittleTitle(),
                bookDataMap.get(cricketId).getTotalCount(),
                master.getValue(),
                son.getValue()
        ));
        // 获得蛐蛐同步消息
        CricketProto.CricketGetSyncMsg.Builder builder = CricketProto.CricketGetSyncMsg.newBuilder();
        builder.setCricketChange(CricketPb.parseCricketDataChange(cricketData));
        builder.setCricketScore(scoreAdd);
        player.sendPacket(ClientProtocol.U_CRICKET_GET_SYNC, builder);
        return cricketData;
    }


    /**
     * 初始化蛐蛐
     *
     * @param cricketId 蛐蛐id
     */
    public CricketData initCricket(int cricketId) {
        CricketData cricketData = CricketMgr.initCricket(cricketId, player.getUserId());
        return cricketData;
    }

    /**
     * 获取资质
     */
    public CricketTalent calcCricketTalent(CricketData cricketData) {
        CricketTalent cricketTalent = new CricketTalent();
        if (cricketData == null) {
            return cricketTalent;
        }
        CricketConfig config = CricketMgr.getConfig().getCricketConfig(cricketData.getCricketId());
        if (config == null) {
            return cricketTalent;
        }
        // 血攻气资质
        List<Integer> configTalentList = StringUtils.stringToIntegerList(config.getTalent(), "\\|");
        List<Integer> maxTalentList = StringUtils.stringToIntegerList(GameConfig.CRICKET_MAX_TALENT, "\\|");
        // 血
        cricketTalent.setHp(Math.min(maxTalentList.get(0), configTalentList.get(0)));
        // 攻
        cricketTalent.setAtk(Math.min(maxTalentList.get(1), configTalentList.get(1)));
        // 气
        cricketTalent.setPower(Math.min(maxTalentList.get(2), configTalentList.get(2)));
        cricketData.setCricketTalent(cricketTalent);
        return cricketTalent;
    }

    /**
     * 更新蛐蛐数据
     *
     * @param cricketData 蛐蛐数据
     */
    public void cricketDataChange(CricketData cricketData) {
        if (cricketData == null) {
            return;
        }
        CricketConfig config = CricketMgr.getConfig().getCricketConfig(cricketData.getCricketId());
        if (config == null) {
            return;
        }
        // 检测蛐蛐技能
        checkCricketSkill(cricketData);
        // 计算最终属性
        calcProperty(cricketData);
        // 保存数据
        cricketDataMap.put(cricketData.getCricketId(), cricketData);
        // 有数据变更的蛐蛐添加到防守阵容中，新获得的蛐蛐会调用到这里
        addCricketDefense(cricketData);
        // 同步蛐蛐信息
        syncCricketData(cricketData);
    }


    /**
     * 蛐蛐新增被动技能
     *
     * @param cricketData 蛐蛐数据
     */
    private void addCricketSkill(CricketData cricketData) {
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return;
        }
        if (cricketData == null) {
            return;
        }

        Set<Integer> skillIdSet = new HashSet<>();
        for (CricketSkill cricketSkill : cricketData.getSkillList()) {
            skillIdSet.add(cricketSkill.getSkillId());
        }
        // 随机一个技能
        int skillId = randomSkillId(skillIdSet, 0);
        if (skillId == 0) {
            return;
        }
        SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
        if (skillInfo == null) {
            log.warn("蛐蛐技能id:{} ,配置为空", skillId);
            return;
        }

        // 添加技能
        addSkill(cricketData, skillId);
    }


    public void resetRepeatCricketSkill(CricketData cricketData) {

    }

    /**
     * 随机一个被动技能
     */
    public int randomSkillId() {
        return randomSkillId(new HashSet<>(), 0);
    }

    /**
     * 随机一个被动技能 star = 0 不限制星级
     *
     * @param exclusiveSkillIdSet 排除技能
     */
    public int randomSkillId(Set<Integer> exclusiveSkillIdSet, int star) {
        int skillId = 0;
        String weightStr = GameConfig.CRICKET_SKILLS_GET_WEIGHT;
        List<String> weightList = StringUtils.stringToStringList(weightStr, "\\|");

        List<String> newWeightList = new ArrayList<>();
        // 总权重
        int sumWeight = 0;
        for (String s : weightList) {
            String[] split = s.split(";");
            int id = Integer.parseInt(split[0]);

            SkillInfo skillInfo = SkillMgr.getSkillInfo(id);
            if (skillInfo == null) {
                continue;
            }
            if (star > 0 && skillInfo.getStars() != star) {
                continue;
            }

            if (exclusiveSkillIdSet.contains(id)) {
                continue;
            }
            sumWeight += Integer.parseInt(split[1]);
            newWeightList.add(s);
        }
        // 随机一个权重
        int randomWeight = randomHelper.next(0, sumWeight);
        // 当前权重
        int curWeight = 0;
        for (String s : newWeightList) {
            String[] split = s.split(";");
            int id = Integer.parseInt(split[0]);
            curWeight += Integer.parseInt(split[1]);
            if (randomWeight < curWeight) {
                skillId = id;
                break;
            }
        }
        return skillId;
    }

    /**
     * 蛐蛐升阶
     *
     * @param cricketId 蛐蛐id
     */
    public int cricketUpgrade(int cricketId) {
        if (cricketId == -1) {
            // 传-1视为一键升阶
            return cricketOneKeyUpgrade();
        }
        CricketData cricketData = getCricketData(cricketId);
        if (cricketData == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        // 当前军衔
        int title = cricketData.getTitle();
        // 当前品阶
        int littleTitle = cricketData.getLittleTitle();
        // 检验消耗
        CricketUpConfig cricketUpConfig = CricketMgr.getCricketUpConfig(cricketId, title, littleTitle);
        if (cricketUpConfig == null) {
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        // 判断当前军衔的品阶是否升到满级
        CricketUpConfig nextCricketUpConfig = CricketMgr.getNextCricketUpConfig(cricketId, title, littleTitle);
        if (nextCricketUpConfig == null) {
            return GameErrorCode.E_CRICKET_UPGRADE_LIMIT;
        }
        // 判断消耗是否足够
        if (!removeItem(new Property(cricketId, cricketUpConfig.getSelfConsume()))) {
            //触发现金礼包
            player.notifyListener(eGamePlayerEventType.RechargeCricketTrain.getValue(), 0);

            return GameErrorCode.E_CRICKET_UPGRADE_NO_ENOUGH;
        }
        // 拷贝一份升级前的数据
        CricketData originCricketData = cricketData.clone();
        // 升至下一品
        cricketData.setTitle(nextCricketUpConfig.getTitle());
        cricketData.setLittleTitle(nextCricketUpConfig.getLittleTitle());
        // 是否解锁新技能槽
        if (cricketUpConfig.getUnlockSkill() == 1) {
            addCricketSkill(cricketData);
            // 技能变动
            skillChange();
        }
        // 蛐蛐数据变更
        cricketDataChange(cricketData);
        // 获得道具
        String reward = cricketUpConfig.getReward();
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Cricket, eLogMoneyType.CricketUpgradeReward);
        player.notifyListener(eGamePlayerEventType.CricketUpTitle.getValue(), new CricketTiTleArgs(cricketId, cricketData.getTitle(), cricketData.getLittleTitle()));
        CricketProto.CricketUpgradeRespMsg.Builder respMsg = CricketProto.CricketUpgradeRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.addOriginCricket(CricketPb.parseCricketTemp(originCricketData));
        respMsg.addCricket(CricketPb.parseCricketTemp(cricketData));
        respMsg.setReward(reward);
        player.sendPacket(ClientProtocol.U_CRICKET_CRICKET_UPGRADE, respMsg);
        // 同步道具信息
        syncCricketItemData();
        // 升阶日志
        AutoLogMgr.add(new LogCricketUpgrade(
                player.getUserId(),
                cricketId,
                cricketData.getQuality(),
                originCricketData.getTitle(),
                originCricketData.getLittleTitle(),
                originCricketData.getCricketProperty().getHp() + originCricketData.getAddProperty().getHp(),
                originCricketData.getCricketProperty().getAtk() + originCricketData.getAddProperty().getAtk(),
                originCricketData.getCricketProperty().getPower() + originCricketData.getAddProperty().getPower(),
                originCricketData.getCricketProperty().getAbility() + originCricketData.getAddProperty().getAbility(),
                cricketData.getTitle(),
                cricketData.getLittleTitle(),
                cricketData.getCricketProperty().getHp() + cricketData.getAddProperty().getHp(),
                cricketData.getCricketProperty().getAtk() + cricketData.getAddProperty().getAtk(),
                cricketData.getCricketProperty().getPower() + cricketData.getAddProperty().getPower(),
                cricketData.getCricketProperty().getAbility() + cricketData.getAddProperty().getAbility(),
                cricketUpConfig.getSelfConsume(),
                cricketUpConfig.getReward()
        ));
        return 0;
    }

    /**
     * 蛐蛐一键升阶
     */
    public int cricketOneKeyUpgrade() {
        CricketProto.CricketUpgradeRespMsg.Builder respMsg = CricketProto.CricketUpgradeRespMsg.newBuilder();
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        // 活动奖励
        Property reward = new Property();
        // 检验消耗
        for (CricketData cricketData : cricketDataMap.values()) {
            boolean isChange = false;
            // 拷贝一份升级前的数据
            CricketData originCricketData = cricketData.clone();
            // 升阶奖励
            Property upReward = new Property();
            // 消耗数量
            int consumeNum = 0;
            for (int i = 0; i < 1000; i++) {
                CricketUpConfig cricketUpConfig = CricketMgr.getCricketUpConfig(cricketData.getCricketId(), cricketData.getTitle(), cricketData.getLittleTitle());
                if (cricketUpConfig == null) {
                    // 找不到配置
                    break;
                }
                // 判断当前军衔的品阶是否升到满级
                CricketUpConfig nextCricketUpConfig = CricketMgr.getNextCricketUpConfig(cricketData.getCricketId(), cricketData.getTitle(), cricketData.getLittleTitle());
                if (nextCricketUpConfig == null) {
                    break;
                }
                // 判断消耗是否足够
                if (!enoughItem(new Property(cricketData.getCricketId(), cricketUpConfig.getSelfConsume()))) {
                    break;
                }
                // 开始升阶

                // 先扣除
                if (!removeItem(new Property(cricketData.getCricketId(), cricketUpConfig.getSelfConsume()))) {
                    break;
                }
                consumeNum += cricketUpConfig.getSelfConsume();

                // 升至下一品
                cricketData.setTitle(nextCricketUpConfig.getTitle());
                cricketData.setLittleTitle(nextCricketUpConfig.getLittleTitle());
                isChange = true;
                // 是否解锁新技能槽
                if (cricketUpConfig.getUnlockSkill() == 1) {
                    addCricketSkill(cricketData);
                    // 技能变动
                    skillChange();
                }
                upReward.addProperty(PropertyHelper.parseStringToProperty(cricketUpConfig.getReward()));
                // 每次升级都要触发
                player.notifyListener(eGamePlayerEventType.CricketUpTitle.getValue(), new CricketTiTleArgs(cricketData.getCricketId(), cricketData.getTitle(), cricketData.getLittleTitle()));
            }
            if (isChange) {
                reward.addProperty(upReward);
                // 蛐蛐数据变更
                cricketDataChange(cricketData);

                respMsg.addOriginCricket(CricketPb.parseCricketTemp(originCricketData));
                respMsg.addCricket(CricketPb.parseCricketTemp(cricketData));
                // 升阶日志
                AutoLogMgr.add(new LogCricketUpgrade(
                        player.getUserId(),
                        cricketData.getCricketId(),
                        cricketData.getQuality(),
                        originCricketData.getTitle(),
                        originCricketData.getLittleTitle(),
                        originCricketData.getCricketProperty().getHp() + originCricketData.getAddProperty().getHp(),
                        originCricketData.getCricketProperty().getAtk() + originCricketData.getAddProperty().getAtk(),
                        originCricketData.getCricketProperty().getPower() + originCricketData.getAddProperty().getPower(),
                        originCricketData.getCricketProperty().getAbility() + originCricketData.getAddProperty().getAbility(),
                        cricketData.getTitle(),
                        cricketData.getLittleTitle(),
                        cricketData.getCricketProperty().getHp() + cricketData.getAddProperty().getHp(),
                        cricketData.getCricketProperty().getAtk() + cricketData.getAddProperty().getAtk(),
                        cricketData.getCricketProperty().getPower() + cricketData.getAddProperty().getPower(),
                        cricketData.getCricketProperty().getAbility() + cricketData.getAddProperty().getAbility(),
                        consumeNum,
                        PropertyHelper.parsePropertyToString(upReward)
                ));
            }
        }
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Cricket, eLogMoneyType.CricketUpgradeReward);

        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        player.sendPacket(ClientProtocol.U_CRICKET_CRICKET_UPGRADE, respMsg);
        // 同步道具信息
        syncCricketItemData();
        return 0;
    }

    /**
     * 添加被动技能
     *
     * @param cricketData 蛐蛐数据
     * @param skillId     蛐蛐id
     */
    private void addSkill(CricketData cricketData, int skillId) {
        if (cricketData == null) {
            return;
        }
        List<CricketSkill> skillList = cricketData.getSkillList();
        skillList.add(new CricketSkill(skillId));
        cricketData.setSkillList(skillList);
    }

    /**
     * 替换技能
     *
     * @param cricketData 蛐蛐数据
     * @param skillId     技能id
     * @param index       技能索引
     */
    private void replaceSkill(CricketData cricketData, int skillId, int index) {
        if (cricketData == null) {
            return;
        }
        List<CricketSkill> skillList = cricketData.getSkillList();
        CricketSkill cricketSkill = new CricketSkill(skillId);
        skillList.set(index, cricketSkill);
        cricketData.setSkillList(skillList);
    }

    /**
     * 技能变动
     */
    private void skillChange() {
        if (userCricketData == null) {
            return;
        }
        // 被动技能星级
        player.notifyListener(eGamePlayerEventType.CricketPassiveSkillLevel.getValue(), getPassiveSkillLevel());
    }

    /**
     * 升级勋章
     */
    public int upgradeCricketBadge() {
        BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.Cricket.getValue(), userCricketData.getBadgeLevel());
        if (cricketBadgeConfig == null) {
            return GameErrorCode.E_CRICKET_BADGE_UPGRADE_LEVEL_MAX;
        }
        if (cricketBadgeConfig.getUnlockValue() == 0) {
            return GameErrorCode.E_CRICKET_BADGE_UPGRADE_LEVEL_MAX;
        }

        if (userCricketData.getCricketScore() < cricketBadgeConfig.getUnlockValue()) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        BadgeConfig cricketBadgeConfigNext = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.Cricket.getValue(), userCricketData.getBadgeLevel() + 1);
        if (cricketBadgeConfigNext == null) {
            return GameErrorCode.E_CRICKET_BADGE_UPGRADE_LEVEL_MAX;
        }

        userCricketData.setBadgeLevel(userCricketData.getBadgeLevel() + 1);
        //同步商铺赚速
        player.getModule(EarnSpeedModule.class).scheduleAddSilver();
        // 更新勋章
        updateBadge();
        changeCricketScoreRank();
        CricketProto.CricketBadgeUpgradeRespMsg.Builder respMsg = CricketProto.CricketBadgeUpgradeRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setBadgeLevel(userCricketData.getBadgeLevel());
        player.sendPacket(ClientProtocol.U_CRICKET_BADGE_UPGRADE, respMsg);
        return 0;
    }

    /**
     * 初始化竞技场勋章
     */
    public void initCricketCourtBadge() {
        if (!SystemOpenMgr.systemOpen(player, eSystemId.BadgeShow.getValue()) || !SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            // 系统未开放
            return;
        }
        if (userCricketData.getCourtBadgeId() != 0) {
            return;
        }
        // 初始化等级
        int initLevel = 1;
        BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.CricketCourt.getValue(), initLevel);
        if (cricketBadgeConfig == null) {
            return;
        }
        userCricketData.setCourtBadgeId(cricketBadgeConfig.getId());
        // 更新勋章
        updateCourtBadge();
        // 上传到跨服
        uploadCricketCourtBadgeToCross();
    }

    /**
     * 增加勋章经验
     * @param addExp 经验
     */
    public void addCricketCourtBadgeExp(BigInteger addExp) {
        if (userCricketData == null) {
            return;
        }
        userCricketData.setCourtBadgeExp(userCricketData.getCourtBadgeExp() + addExp.longValue());
        upgradeCricketCourtBadge();
        // 同步一下数据
        syncUserData();
    }

    /**
     * 竞技场勋章变动
     */
    public void upgradeCricketCourtBadge() {
        BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfig(eBadgeType.CricketCourt.getValue(), userCricketData.getCourtBadgeId());
        if (cricketBadgeConfig == null) {
            return;
        }
        // 满级了不需要再处理
        if (cricketBadgeConfig.getUnlockValue() == 0) {
            return;
        }
        // 升级
        BadgeConfig cricketBadgeConfigNext = null;
        while ((cricketBadgeConfigNext = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.CricketCourt.getValue(), cricketBadgeConfig.getLevel() + 1)) != null) {
            // 经验不够
            if (userCricketData.getCourtBadgeExp() < cricketBadgeConfig.getUnlockValue()) {
                break;
            }
            userCricketData.setCourtBadgeId(cricketBadgeConfigNext.getId());
            cricketBadgeConfig = cricketBadgeConfigNext;
        }
        // 更新勋章
        updateCourtBadge();
        // 上传到跨服
        uploadCricketCourtBadgeToCross();
    }


    /**
     * 计算属性
     *
     * @param cricketData 蛐蛐数据
     */
    public void calcProperty(CricketData cricketData) {
        CricketMgr.calcProperty(cricketData);
    }

    /**
     * 获取生效的技能(过滤掉不生效、低星级不可叠加的技能)
     */
    public List<CricketSkill> getAllEffectSkill(CricketData cricketData) {
        return CricketMgr.getAllEffectSkill(cricketData);
    }


    /**
     * 计算技能buff属性加成
     *
     * @param cricketData 蛐蛐数据
     */
    public void calcBuffAddProperty(CricketData cricketData) {
        CricketMgr.calcBuffAddProperty(cricketData);
    }


    /**
     * 同步单个蛐蛐信息
     */
    public void syncCricketData(CricketData cricketData) {
        if (cricketData != null) {
            List<CricketData> syncList = new ArrayList<>();
            syncList.add(cricketData);
            syncCricketData(syncList);
        }
    }

    /**
     * 同步蛐蛐数据
     *
     * @param syncList 同步列表
     */
    private void syncCricketData(List<CricketData> syncList) {
        CricketProto.CricketDataSyncMsg.Builder builder = CricketProto.CricketDataSyncMsg.newBuilder();
        for (CricketData cricketData : syncList) {
            builder.addCricket(CricketPb.parseCricketTemp(cricketData));
        }
        builder.addAllDefenseCricketId(this.getUserCricketData().getCricketMatchData().getDefenseList());
        player.sendPacket(Protocol.U_CRICKET_SYNC, builder);
    }


    /**
     * 更新勋章
     */
    public void updateBadge() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.BadgeShow.getValue()) && SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            if (userCricketData == null) {
                return;
            }
            BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.Cricket.getValue(), userCricketData.getBadgeLevel());
            if (cricketBadgeConfig == null) {
                return;
            }
            player.getModule(BadgeModule.class).addBadge(cricketBadgeConfig.getId(), eBadgeType.Cricket.getValue());
        }
    }


    /**
     * 更新勋章
     */
    public void updateCourtBadge() {
        if (SystemOpenMgr.systemOpen(player, eSystemId.BadgeShow.getValue()) && SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            if (userCricketData == null) {
                return;
            }
            BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfig(eBadgeType.CricketCourt.getValue(), userCricketData.getCourtBadgeId());
            if (cricketBadgeConfig == null) {
                return;
            }
            player.getModule(BadgeModule.class).addBadge(cricketBadgeConfig.getId(), eBadgeType.CricketCourt.getValue());
        }
    }

    public int getStageSkillMaxLevelAdd() {
        int addValue = 0;
        if (!SystemOpenMgr.systemOpen(player, eSystemId.BadgeShow.getValue()) || !SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            return addValue;
        }

        BadgeConfig cricketBadgeConfig = BadgeConfigMgr.getBadgeConfigByLevel(eBadgeType.Cricket.getValue(), userCricketData.getBadgeLevel());
        if (cricketBadgeConfig == null) {
            return addValue;
        }
        for (Integer skillId : cricketBadgeConfig.getSkillIdList()) {
            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
            if (skillInfo != null && skillInfo.getType() == eSkillType.FishPondStageSkillMaxLevelAdd.getValue()) {
                addValue += SkillMgr.getSkillAddition(skillInfo, userCricketData.getBadgeLevel());
            }
        }
        return addValue;
    }

    public UserCricketData getUserCricketData() {
        if (userCricketData == null) {
            return null;
        }
        CricketMgr.refreshUserCricketData(userCricketData);
        return userCricketData;
    }


    /**
     * 增加虫师积分
     *
     * @param count 积分数量
     */
    public void addCricketScore(BigInteger count) {
        if (userCricketData == null) {
            return;
        }
        userCricketData.setCricketScore(userCricketData.getCricketScore() + count.longValue());
        player.notifyListener(eGamePlayerEventType.CricketScoreRise.getValue(),count.longValue());
        changeCricketScoreRank();
        // 同步用户信息
        syncUserData();
    }


    public CricketData getCricketData(int cricketId) {
        return cricketDataMap.get(cricketId);
    }


    public void changeCourtRound(int round) {
        // 判断下是否切换轮次
        if (userCricketData.getCourtRound() == round) {
            return;
        }
        CricketMatchData cricketMatchData = userCricketData.getCricketMatchData();
        if (cricketMatchData != null) {
            cricketMatchData.setTargetDefenseData(null);
            cricketMatchData.setPreReduceProperty(null);
        }
        // 回到初始分
        userCricketData.setCourtRound(round);
        userCricketData.setRankScore(GameConfig.CRICKET_FIGHT_BEGIN_RANK_SCORE);
        userCricketData.setShowCourtRank(false);
        userCricketData.setUpdateOption();

        // 刷新蛐蛐数据
        for (CricketData cricketData : cricketDataMap.values()) {
            cricketData.setMatchTimes(0);
            cricketData.setLastMatchTime(System.currentTimeMillis());
        }
        // 同步下用户数据
        syncUserData();
    }


    public boolean isCricketMatchFree(CricketData cricketData) {
        return cricketData.getMatchTimes() < GameConfig.CRICKET_FIGHT_OUT_FREE_MAX;
    }

    public boolean isCricketMatchMax(CricketData cricketData) {
        int cricketFightOutMax = GameConfig.CRICKET_FIGHT_OUT_MAX;
        return cricketData.getMatchTimes() >= cricketFightOutMax;
    }


    /**
     * 增加道具
     *
     * @param change 道具变更
     */
    private void addItem(Property change) {
        userCricketData.getItems().addProperty(change);
        userCricketData.setUpdateOption();
    }

    /**
     * 消耗道具
     *
     * @param change 道具变更
     */
    private boolean removeItem(Property change) {
        // 先判断够不够
        if (!enoughItem(change)) {
            return false;
        }
        // 扣道具
        for (Map.Entry<Integer, BigInteger> entry : change.getGoods().entrySet()) {
            Integer itemId = entry.getKey();
            BigInteger count = entry.getValue();
            userCricketData.getItems().removeProperty(itemId, count);
        }
        userCricketData.setUpdateOption();
        return true;
    }

    /**
     * 道具是否足够
     * @param property
     * @return
     */
    private boolean enoughItem(Property property) {
        // 判断消耗够不够
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            Integer itemId = entry.getKey();
            BigInteger count = entry.getValue();
            if (userCricketData.getItems().getCountByGoodsId(itemId).compareTo(count) < 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 增加图鉴
     *
     * @param cricketId 蛐蛐id
     */
    public void addBook(int cricketId, int count) {
        CricketConfig config = CricketMgr.getConfig().getCricketConfigMap().get(cricketId);
        if (config == null) {
            return;
        }
        int oldSize = bookDataMap.size();
        CricketBookData cricketBookData = bookDataMap.get(cricketId);
        if (cricketBookData == null) {
            cricketBookData = new CricketBookData();
            cricketBookData.setUserId(player.getUserId());
            cricketBookData.setCricketId(cricketId);
            cricketBookData.setTotalCount(count);
            cricketBookData.setInsertOption();
        } else {
            cricketBookData.setTotalCount(cricketBookData.getTotalCount() + count);
        }
        bookDataMap.put(cricketId, cricketBookData);
        //促织基金
        int newSize = bookDataMap.size();
        if(newSize != oldSize) {
            player.notifyListener(eGamePlayerEventType.CricketFund.getValue(), bookDataMap.size());
        }
    }

    /**
     * 检测蛐蛐技能
     *
     * @param cricketData 蛐蛐数据
     */
    public void checkCricketSkill(CricketData cricketData) {
        if (cricketData == null) {
            return;
        }
        initSkill(cricketData);
        // 可学习的被动技能数
        int canLearnSkillNum = canLearnSkillNum(cricketData);
        // 当前学习的被动技能数
        int skillNum = cricketData.getSkillList().size();
        if (skillNum >= canLearnSkillNum) {
            return;
        }
        // 需要学习的被动技能数
        int needLearnNum = canLearnSkillNum - skillNum;
        for (int i = 0; i < needLearnNum; i++) {
            addCricketSkill(cricketData);
        }
        // 技能变动
        skillChange();

        //检查是否有重复的技能，如果有，则将会重新随机一个同星级且不冲突的技能替换原来的同名技能

        HashMap<Integer, CricketSkill> skillMap = new HashMap<>();
        ArrayList<CricketSkill> repeatSkill = new ArrayList<>();
        Set<Integer> skillIdSet = new HashSet<>();

        for (CricketSkill cricketSkill : cricketData.getSkillList()) {
            if (!skillMap.containsKey(cricketSkill.getSkillId())) {
                skillMap.put(cricketSkill.getSkillId(), cricketSkill);
                continue;
            }
            skillIdSet.add(cricketSkill.getSkillId());
            repeatSkill.add(cricketSkill);
        }

        cricketData.getSkillList().clear();
        cricketData.getSkillList().addAll(skillMap.values());


        for (CricketSkill cricketSkill : repeatSkill) {

            SkillInfo skillInfo = SkillMgr.getSkillInfo(cricketSkill.getSkillId());
            if (skillInfo == null) {
                continue;
            }
            int randomSkillId = randomSkillId(skillIdSet, skillInfo.getStars());
            skillIdSet.add(randomSkillId);
            CricketSkill cricketSkill1 = new CricketSkill();
            cricketSkill1.setSkillId(randomSkillId);
            cricketData.getSkillList().add(cricketSkill1);
        }

        cricketData.setUpdateOption();

        //新的通用技能

    }

    /**
     * 初始攻击方式和天赋
     *
     * @param cricketData 蛐蛐数据
     */
    private void initSkill(CricketData cricketData) {
        if (cricketData == null) {
            return;
        }
        int cricketId = cricketData.getCricketId();
        CricketSystemConfig config = CricketMgr.getConfig();
        CricketConfig cricketConfig = config.getCricketConfig(cricketId);
        if (cricketConfig == null) {
            return;
        }
        // 攻击列表
        List<CricketSkill> attackSkillList = new ArrayList<>();
        List<Integer> attackConfigSkillList = cricketConfig.getAttackSkillList();
        for (int skillId : attackConfigSkillList) {
            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
            if (skillInfo == null) {
                // 判断下技能是否存在
                continue;
            }
            if (attackSkillList.stream().anyMatch(cricketSkill -> skillId == cricketSkill.getSkillId())) {
                // 已添加
                continue;
            }
            attackSkillList.add(new CricketSkill(skillId));
        }
        cricketData.setAttackSkillList(attackSkillList);
        // 初始天赋
        List<CricketSkill> initSkillList = new ArrayList<>();
        List<Integer> initConfigSkillList = cricketConfig.getInitSkillList();
        for (int skillId : initConfigSkillList) {
            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
            if (skillInfo == null) {
                // 判断下技能是否存在
                continue;
            }
            if (initSkillList.stream().anyMatch(cricketSkill -> skillId == cricketSkill.getSkillId())) {
                // 已添加
                continue;
            }
            initSkillList.add(new CricketSkill(skillId));
        }
        cricketData.setInitSkillList(initSkillList);

        List<CricketEquipSkill> eSkillList = cricketData.getEquipSkillList();
        List<Integer> eSkillConfigList = cricketConfig.getEquipSkillList();
        for (int skillId : eSkillConfigList) {
            SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
            if (skillInfo == null) {
                // 判断下技能是否存在
                continue;
            }
            if (eSkillList.stream().anyMatch(a -> skillId == a.getSkillId())) {
                // 已添加
                continue;
            }
            CricketEquipSkill newSkill = new CricketEquipSkill();
            newSkill.setUserId(getUserId());
            newSkill.setCricketId(cricketId);
            newSkill.setSkillId(skillId);
            newSkill.setLv(1);
            newSkill.setInsertOption();
            eSkillList.add(newSkill);
        }

        cricketData.setEquipSkillList(eSkillList);
    }


    /**
     * 蛐蛐能学习几个被动技能
     *
     * @param cricketData 蛐蛐信息
     */
    public int canLearnSkillNum(CricketData cricketData) {
        int skillNum = 0;
        if (cricketData == null) {
            return skillNum;
        }
        CricketSystemConfig config = CricketMgr.getConfig();
        if (config == null) {
            return skillNum;
        }
        int cricketId = cricketData.getCricketId();
        CricketConfig cricketConfig = config.getCricketConfig(cricketId);
        if (cricketConfig == null) {
            return skillNum;
        }
        List<Integer> beginTitles = StringUtils.stringToIntegerList(cricketConfig.getBeginTitle(), "\\|");
        CricketUpConfig beginUpConfig = CricketMgr.getCricketUpConfig(cricketId, beginTitles.get(0), beginTitles.get(1));
        if (beginUpConfig == null) {
            return skillNum;
        }
        // 初始升阶id
        int initUpConfigId = beginUpConfig.getId();
        CricketUpConfig currentUpConfig = CricketMgr.getCricketUpConfig(cricketId, cricketData.getTitle(), cricketData.getLittleTitle());
        if (currentUpConfig == null) {
            return skillNum;
        }
        // 当前升阶id
        int currentUpConfigId = currentUpConfig.getId();
        Map<Integer, CricketUpConfig> cricketUpConfigMap = config.getCricketUpConfigMap();
        for (CricketUpConfig upConfig : cricketUpConfigMap.values()) {
            if (cricketConfig.getQuality() != upConfig.getCricketQuality()) {
                continue;
            }
            if (upConfig.getUnlockSkill() != 1) {
                continue;
            }
            // 升阶id大于初始阶段的id且小于当前的升阶id，（当前的升阶id解锁的是下一等级的）
            if (upConfig.getId() >= initUpConfigId && upConfig.getId() < currentUpConfigId) {
                skillNum++;
            }
        }
        return skillNum;
    }

    /**
     * 当前蛐蛐达到满级需要多少个本体材料
     */
    public int countOfMaxLevel(CricketData cricketData) {
        int totalCount = 0;
        CricketSystemConfig config = CricketMgr.getConfig();
        int cricketId = cricketData.getCricketId();
        // 当前拥有数量
        int haveCount = 0;
        if (null != userCricketData) {
            haveCount = userCricketData.getItems().getCountByGoodsId(cricketId).intValue();
        }

        // 当前军衔
        int title = cricketData.getTitle();
        // 当前品阶
        int littleTitle = cricketData.getLittleTitle();
        // 获取当前品阶配置
        CricketUpConfig currentUpConfig = CricketMgr.getCricketUpConfig(cricketId, title, littleTitle);
        // 获取下一品阶配置
        CricketUpConfig nextUpConfig = CricketMgr.getNextCricketUpConfig(cricketId, title, littleTitle);
        while (currentUpConfig != null && nextUpConfig != null) {
            totalCount += currentUpConfig.getSelfConsume();
            currentUpConfig = nextUpConfig;
            nextUpConfig = CricketMgr.getNextCricketUpConfig(cricketId, currentUpConfig.getTitle(), currentUpConfig.getLittleTitle());
        }
        return Math.max(0, totalCount - haveCount);
    }

    public void addDbCricketBattleLog(DbUserCricketBattleLog dbCricketHotBattleLog) {
        int limit = GameConfig.CRICKET_FIGHT_REPORT_MY_MAX_NUM;
        synchronized (this.cricketBattleLogList) {
            this.cricketBattleLogList.add(dbCricketHotBattleLog);
            if (this.cricketBattleLogList.size() > limit) {
                this.cricketBattleLogList.remove(0);
            }
        }
    }


    public List<DbUserCricketBattleLog> getCricketBattleLogList() {
        ArrayList<DbUserCricketBattleLog> dbUserCricketBattleLogs = new ArrayList<>(this.cricketBattleLogList);
        return dbUserCricketBattleLogs;
    }

    /**
     * 战斗结算
     *
     * @param battleLog
     * @param courtId
     * @param groupId
     */
    public void handleGameBattleLog(CricketProto.CricketBattleLog.Builder battleLog, CricketProto.CricketUserBattleMatchDataTemp cricketUserBattleMatchDataTemp, int round, int courtId, int groupId) {
        // 清空一下
        userCricketData.getCricketMatchData().setTargetDefenseData(null);
        userCricketData.setUpdateOption();

        Set<Integer> cricketSet = new HashSet<>();

        CricketProto.CricketMatchRound matchRound = battleLog.getMatchRound();

        List<LogCricket> logMyCricketList = new ArrayList<>();
        List<LogCricket> logTargetCricketList = new ArrayList<>();
        long totalAbility = 0;

        int winNum = 0;
        //参战的蛐蛐
        for (CricketProto.CricketGameRound cricketGameRound : matchRound.getGameRoundList()) {
            //自已参战的蛐蛐
            CricketProto.CricketMatchDataTemp myCricketMatchDataTemp = null;
            for (CricketProto.CricketMatchDataTemp cricketMatchDataTemp : cricketGameRound.getCricketList()) {
                LogCricket logCricket = new LogCricket();
                logCricket.setCricketId(cricketMatchDataTemp.getCricketId());
                logCricket.setQuality(cricketMatchDataTemp.getQuality());
                logCricket.setTitle(cricketMatchDataTemp.getTitle());
                logCricket.setLittleTitle(cricketMatchDataTemp.getLittleTitle());
                logCricket.setPower(cricketMatchDataTemp.getProperty().getPower());
                logCricket.setHp(cricketMatchDataTemp.getProperty().getHp());
                logCricket.setAtk(cricketMatchDataTemp.getProperty().getAtk());
                logCricket.setAbility(cricketMatchDataTemp.getProperty().getAbility());
                List<CricketProto.CricketSkillTempMsg> skillList = cricketMatchDataTemp.getSkillList();
                StringBuilder stringBuilder = new StringBuilder();
                for (CricketProto.CricketSkillTempMsg cricketSkillTempMsg : skillList) {
                    stringBuilder.append(cricketSkillTempMsg.getSkillId());
                    stringBuilder.append(";");
                }
                logCricket.setSkillList(stringBuilder.toString());
                if (cricketMatchDataTemp.getUserId() == player.getUserId()) {
                    myCricketMatchDataTemp = cricketMatchDataTemp;
                    if (cricketGameRound.getWinUserId() == player.getUserId()) {
                        logCricket.setWin(true);
                        winNum++;
                    }
                    logMyCricketList.add(logCricket);
                } else {
                    if (cricketGameRound.getWinUserId() != player.getUserId()) {
                        logCricket.setWin(true);
                    }
                    logTargetCricketList.add(logCricket);
                }
                totalAbility = totalAbility + cricketMatchDataTemp.getProperty().getAbility();
            }
            if (myCricketMatchDataTemp != null) {
                cricketSet.add(myCricketMatchDataTemp.getCricketId());
                CricketData cricketData = this.getCricketData(myCricketMatchDataTemp.getCricketId());
                cricketData.setBattleTimes(cricketData.getBattleTimes() + 1);
                if (cricketGameRound.getWinUserId() == player.getUserId()) {
                    cricketData.setBattleWinTimes(cricketData.getBattleWinTimes() + 1);
                }
                cricketData.setUpdateOption();
            }

        }

        UserCricketData userCricketData = getUserCricketData();
        List<CricketData> updateCricketDataList = new ArrayList<>();
        //增加蛐蛐匹配次数
        for (int cricketId : cricketSet) {
            CricketData cricketData = this.getCricketData(cricketId);
            cricketData.setMatchTimes(cricketData.getMatchTimes() + 1);
            cricketData.setUpdateOption();
            updateCricketDataList.add(cricketData);
        }

        this.syncCricketData(updateCricketDataList);

        //战斗奖励
        Property property = null;
        long addRankScore = 0;
        long targetAddRankScore = 0;

        boolean isWin = false;
        // 获取竞技场结算奖励
        CricketCourtConfig cricketCourtConfig = CricketMgr.getConfig().getCricketCourtConfig(courtId);
        List<String> courtReward = StringUtils.stringToStringList(cricketCourtConfig.getReward(), "\\|");
        if (matchRound.getWinUserId() == player.getUserId()) {
            isWin = true;
            addRankScore = cricketUserBattleMatchDataTemp.getWinScore();
            targetAddRankScore = cricketUserBattleMatchDataTemp.getDefenderFailScore();
            int cricketFightScoreAttack = CricketMgr.getCricketFightScoreAttack(winNum);
            int cricketFightScoreDefend = CricketMgr.getCricketFightScoreDefend(GameConfig.CRICKET_FIGHT_DEF_TEAM_NUM - winNum);
            addRankScore = addRankScore + cricketFightScoreAttack;
            targetAddRankScore = targetAddRankScore + cricketFightScoreDefend;
            // 胜利奖励
            property = PropertyHelper.parseStringToProperty(courtReward.get(0));
        } else {
            addRankScore = cricketUserBattleMatchDataTemp.getFailScore();
            targetAddRankScore = cricketUserBattleMatchDataTemp.getDefenderWinScore();
            int cricketFightScoreAttack = CricketMgr.getCricketFightScoreAttack(winNum);
            int cricketFightScoreDefend = CricketMgr.getCricketFightScoreDefend(GameConfig.CRICKET_FIGHT_DEF_TEAM_NUM - winNum);
            addRankScore = addRankScore + cricketFightScoreAttack;
            targetAddRankScore = targetAddRankScore + cricketFightScoreDefend;
            //失败奖励
            property = PropertyHelper.parseStringToProperty(courtReward.get(1));
        }
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Cricket, eLogMoneyType.CricketBattleResult);
        userCricketData.setRankScore(userCricketData.getRankScore() + addRankScore);
        userCricketData.setTotalMatchTimes(userCricketData.getTotalMatchTimes() + 1);
        battleLog.setRankScore(userCricketData.getRankScore());
        battleLog.addAddRankScore((int) addRankScore);
        battleLog.addAddRankScore((int) targetAddRankScore);
        battleLog.setRewards(PropertyHelper.parsePropertyToString(property));


        long targetUserId = matchRound.getUserBattleDataList().get(1).getUserId();
        long targetServerId = matchRound.getUserBattleDataList().get(1).getPlayerBaseData().getServerId();

        long currentTimeMillis = System.currentTimeMillis();
        long battleLogId = CricketMgr.addBattleLog(player.getUserId(), battleLog.build(), 0);

        CricketProto.CricketDefendBattleLogReqMsg.Builder builder = CricketProto.CricketDefendBattleLogReqMsg.newBuilder();
        builder.setUserId(targetUserId);
        builder.setAddRankScore(targetAddRankScore);
        builder.setFromUserId(player.getUserId());
        builder.setIsWin(!isWin);
        builder.setTimestamp(currentTimeMillis);
        builder.setBattleLog(battleLog);
        builder.setOriginId(battleLogId);
        long serverId = GameServer.getInstance().getServerId();
        builder.setOriginServerId(serverId);
        builder.setRound(round);
        //这里先到结算防守的分数，因为如果失败，需要刷新匹配数据给客户端，要重新选择玩家来战斗
        if (targetServerId == serverId) {
            CricketMgr.handleDefendBattleLog(builder.build(), true);
        } else {
            DbUserCricketWaitSendBattleLog dbUserCricketWaitSendBattleLog = DbUserCricketWaitSendBattleLog.getInstance();
            dbUserCricketWaitSendBattleLog.setToServerId(targetServerId);
            dbUserCricketWaitSendBattleLog.setOriginId(battleLogId);
            dbUserCricketWaitSendBattleLog.setUserId(targetUserId);
            dbUserCricketWaitSendBattleLog.setSync(0);
            dbUserCricketWaitSendBattleLog.setBattleLog(builder.build());
            dbUserCricketWaitSendBattleLog.setNeedInsert(true);
//            CricketMgr.getWaitSendSyncCricketDbBattleLog().put(dbUserCricketWaitSendBattleLog.getOriginId(), dbUserCricketWaitSendBattleLog);
            GamePlayerMgr.sendToGameServer(targetServerId, GameProtocol.S_CRICKET_DEFENDER_HANDLE_BATTLE_LOG, player.getUserId(), builder, null);
        }

        long userId = this.player.getUserId();
        long finalAfterRankScore = userCricketData.getRankScore();

        //上传热门战报
        List<Integer> cricketFightReportHotValueLimitList = CricketMgr.getCricketFightReportHotValueLimitList();
        int p1 = cricketFightReportHotValueLimitList.get(0);
        if (totalAbility > p1) {
            CricketProto.CricketBattleLogAddReqMsg.Builder battleLogAddReqBuilder = CricketProto.CricketBattleLogAddReqMsg.newBuilder();
            battleLogAddReqBuilder.setBattleLog(battleLog);
            // 上跨服
            player.sendPacket(Protocol.C_CRICKET_BATTLE_LOG_UPLOAD, battleLogAddReqBuilder);
        }


        //积分变化都要上传
        CricketProto.CricketDefenseRankScoreUpdateReqMsg.Builder defenseRankScoreUpdateReqBuilder = CricketProto.CricketDefenseRankScoreUpdateReqMsg.newBuilder();
        defenseRankScoreUpdateReqBuilder.setUserId(userId);
        defenseRankScoreUpdateReqBuilder.setRankScore(finalAfterRankScore);
        player.sendPacket(Protocol.C_CRICKET_DEFENSE_RANK_SCORE_UPDATE, defenseRankScoreUpdateReqBuilder);


        // 回合数
        Map<Integer, Integer> logGameRoundMap = new ConcurrentHashMap<>();
        for (int i = 0; i < matchRound.getGameRoundList().size(); i++) {
            logGameRoundMap.put(i + 1, matchRound.getGameRoundList().get(i).getMaxRound());
        }

        // 战斗日志
        AutoLogMgr.add(new LogCricketCourtBattle(
                player.getUserId(),
                round,
                courtId,
                groupId,
                targetUserId,
                JSON.toJSONString(logMyCricketList),
                JSON.toJSONString(logTargetCricketList),
                JSON.toJSONString(logGameRoundMap),
                isWin,
                addRankScore,
                finalAfterRankScore,
                PropertyHelper.parsePropertyToString(property)
        ));
        CricketProto.CricketBattleStartRespMsg.Builder respMsg = CricketProto.CricketBattleStartRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setBattleLog(battleLog);
        respMsg.setTotalMatchTimes(userCricketData.getTotalMatchTimes());
        player.sendPacket(ClientProtocol.U_CRICKET_BATTLE_START, respMsg);
    }


    public Map<Integer, CricketData> getCricketDataMap() {
        return cricketDataMap;
    }

    /**
     * 学习(突破)蛐蛐虫师技能
     */
    public int learnPartonSkill(int patronsId, int skillId) {
        PatronsInfo patronsInfo = PatronsMgr.getPatronsInfo(patronsId);
        if (patronsInfo == null) {
            return GameErrorCode.E_PATRONS_NO_FOUND;
        }
        PatronsModule patronsModule = player.getModule(PatronsModule.class);
        UserPatrons userPatrons = patronsModule.getUserPatrons(patronsId);
        if (userPatrons == null) {
            return GameErrorCode.E_PATRONS_NO_FOUND;
        }
        SkillInfo skillInfo = SkillMgr.getSkillInfo(skillId);
        if (skillInfo == null) {
            return GameErrorCode.E_CRICKET_SKILL_NOT_FOUND;
        }
        UserPatronsSkill skill = userPatrons.getPatronsSkill(ePatronsSkillType.Normal.getValue(), skillId);
        if (skill != null) {
            return GameErrorCode.E_PATRONS_CRICKET_SKILL_HAD_LEARN;
        }
        // 检验技能是否能学习
        CricketSystemConfig config = CricketMgr.getConfig();
        CricketConfig cricketConfig = CricketMgr.getCricketConfigByPartonSkill(skillId);
        if (cricketConfig == null) {
            return GameErrorCode.E_CRICKET_CONFIG_NOT_FOUND;
        }
        // 职业不匹配
        if (cricketConfig.getOccupation() != patronsInfo.getOccupation()) {
            return GameErrorCode.E_PATRONS_CRICKET_SKILL_OCCUPATION_ERROR;
        }
        // 蛐蛐是否获得
        CricketData cricketData = getCricketData(cricketConfig.getId());
        if (cricketData == null) {
            return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
        }
        UserPatronsSkill patronsSkill = userPatrons.getPatronsSkill(ePatronsSkillType.Cricket.getValue(), skillId);
        int cricketSkillBreakCount = 0;
        if (patronsSkill != null && !StringUtils.isNullOrEmpty(patronsSkill.getExtraParams())) {
            cricketSkillBreakCount = StringUtils.string2intSafe(patronsSkill.getExtraParams(), 0);
        }
        // 参数
        String partonSkillParam = CricketMgr.getPartonSkillParam(skillInfo.getStars(), cricketSkillBreakCount);
        List<String> paramList = StringUtils.stringToStringList(partonSkillParam, ";");
        // 初始等级上限；门客赚钱增加固定值；门客赚钱增加千分比；突破军衔；突破品级 ；突破消耗道具

        // 所需军衔
        int needTitle = Integer.parseInt(paramList.get(3));
        // 所需品级
        int needLittleTitle = Integer.parseInt(paramList.get(4));
        // 军衔大于可学习，军衔相等判断品级大于等于要求品级
        boolean canLearn = cricketData.getTitle() > needTitle || (cricketData.getTitle() == needTitle && cricketData.getLittleTitle() >= needLittleTitle);
        if (!canLearn) {
            return GameErrorCode.E_CRICKET_PARTON_SKILL_PARAM_NO_ENOUGH;
        }
        // 突破消耗道具
        String cost = paramList.get(5);
        if (!player.getModule(CurrencyModule.class).removeCurrency(PropertyHelper.parseStringToProperty(cost), eLogMoneyType.Cricket, eLogMoneyType.CricketLearnPartonSkill)) {
            //触发现金礼包
            player.notifyListener(eGamePlayerEventType.RechargeCricketTrain.getValue(), 0);
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        if (patronsSkill == null) {
            // 初始化技能
            patronsSkill = PatronsMgr.initUserPatronsSkill(userPatrons, skillId, ePatronsSkillType.Cricket.getValue(), 1, 0);
            patronsModule.addPatronsSkill(userPatrons, patronsSkill);
        } else {
            // 技能突破
            int curBreakCount = StringUtils.string2intSafe(patronsSkill.getExtraParams(), 0);
            patronsSkill.setExtraParams(String.valueOf(curBreakCount + 1));
        }
        patronsModule.onPatronsChange(userPatrons);
        patronsModule.syncPatronsData(userPatrons);
        CricketProto.CricketLearnPartonSkillRespMsg.Builder respMsg = CricketProto.CricketLearnPartonSkillRespMsg.newBuilder();
        respMsg.setRet(0);
        player.sendPacket(ClientProtocol.U_CRICKET_LEARN_PARTON_SKILL, respMsg);
        return 0;
    }

    /**
     * 匹配前的一些检测
     */
    public int preMatch(boolean isRefresh) {
        int ret = isMatchOpen();
        if (ret > 0) {
            return ret;
        }
        if (isRefresh) {
            String cricketFightRefreshCost = GameConfig.CRICKET_FIGHT_REFRESH_COST;
            Property property = PropertyHelper.parseStringToProperty(cricketFightRefreshCost);
            if (!player.getModule(CurrencyModule.class).currencyIsEnough(property)) {
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
        } else {
            CricketMatchData cricketMatchData = userCricketData.getCricketMatchData();
            if (cricketMatchData != null && cricketMatchData.getTargetDefenseData() != null && cricketMatchData.getTargetDefenseData().getBattleDataList().size() > 0) {
                return GameErrorCode.E_ERROR_PARAMETER;
            }
            UserCricketData userCricketData1 = getUserCricketData();
            if (userCricketData1.getCricketMatchData().getPreReduceProperty() != null) {
                return GameErrorCode.E_ERROR_PARAMETER;
            }
        }

        return 0;
    }


    /**
     * 战斗前的一些检测
     */
    public int preBattle(List<Integer> cricketIdList) {

        int ret = isMatchOpen();
        if (ret > 0) {
            return GameErrorCode.E_CRICKET_NOT_MATCH_TIME;
        }

        if (cricketIdList.size() != 3) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        UserCricketData userCricketData1 = getUserCricketData();
        if (userCricketData1.getCricketMatchData().getPreReduceProperty() != null) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        Property property = new Property();

        for (int cricketId : cricketIdList) {
            CricketData cricketData = this.getCricketData(cricketId);
            if (cricketData == null) {
                return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
            }

            if (cricketData.getQuality() < GameConfig.CRICKET_FIGHT_LIMIT) {
                return GameErrorCode.E_CRICKET_CAN_NOT_FIGHT;
            }

            boolean cricketMatchMax = this.isCricketMatchMax(cricketData);
            if (cricketMatchMax) {
                return GameErrorCode.E_CRICKET_MATCH_MAX;
            }

            boolean cricketMatchFree = this.isCricketMatchFree(cricketData);
            if (!cricketMatchFree) {
                property.addProperty(this.getCricketMatchCost(cricketData));
            }
        }

        if (!player.getModule(CurrencyModule.class).currencyIsEnough(property)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        if (!player.getModule(CurrencyModule.class).removeCurrency(property, eLogMoneyType.Cricket, eLogMoneyType.CricketBattleResult)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        return 0;
    }

    public Property getCricketMatchCost(CricketData cricketData) {
        return CricketMgr.getCricketFightOutCost(cricketData.getMatchTimes());
    }

    /**
     * 系统是否开放
     */
    public static boolean courtSystemOpen() {
        if (!channelCourtSystemOpen()) {
            return false;
        }
        Map<Integer, CricketServerGroup> serverGroupMap = CricketServerGroupMgr.getServerGroupMap(ServerListMgr.getChannelId(GameServer.getInstance().getServerId()));
        if (serverGroupMap == null) {
            return false;
        }
        // 是否包含分组
        boolean hasServerGroup = false;
        for (CricketServerGroup serverGroup : serverGroupMap.values()) {
            if (serverGroup.getOpenStatus() == 1 && serverGroup.getServerList().contains(GameServer.getInstance().getServerId())) {
                hasServerGroup = true;
            }
        }
        return serverGroupMap.size() > 0 && hasServerGroup;
    }

    /**
     * 渠道开放
     */
    public static boolean channelCourtSystemOpen() {
        Map<Integer, CricketServerGroup> serverGroupMap = CricketServerGroupMgr.getServerGroupMap(ServerListMgr.getChannelId(GameServer.getInstance().getServerId()));
        if (serverGroupMap == null) {
            return false;
        }
        for (CricketServerGroup serverGroup : serverGroupMap.values()) {
            // 只要有一个分组是关闭的，就当没开
            if (serverGroup.getOpenStatus() == 0) {
                return false;
            }
        }
        return serverGroupMap.size() > 0;
    }

    /**
     * 膜拜
     */
    public int worship() {
        if (!courtSystemOpen()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        if (userCricketData.getWorshipTime() == userCricketData.getCourtRound()) {
            return GameErrorCode.E_CRICKET_WORSHIP_CAN_NOT;
        }
        // 上跨服
        CricketProto.CrossCricketTopRankWorshipReqMsg.Builder reqMsg = CricketProto.CrossCricketTopRankWorshipReqMsg.newBuilder();
        player.sendPacket(Protocol.C_CRICKET_TOP_RANK_WORSHIP, reqMsg);
        return 0;
    }


    public int worshipFormCross(PlayerProto.PlayerBaseTempMsg playerBaseData) {
        if (!courtSystemOpen()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        if (userCricketData.getWorshipTime() == userCricketData.getCourtRound()) {
            return GameErrorCode.E_CRICKET_WORSHIP_CAN_NOT;
        }
        userCricketData.setWorshipTime(userCricketData.getCourtRound());
        String worshipReward = CricketMgr.getWorshipReward();
        player.getModule(CurrencyModule.class).addCurrency(worshipReward, eLogMoneyType.Cricket, eLogMoneyType.CricketWorship);
        CricketProto.CricketTopRankWorshipRespMsg.Builder builder = CricketProto.CricketTopRankWorshipRespMsg.newBuilder();
        builder.setRet(0);
        builder.setPlayerBaseData(playerBaseData);
        builder.setReward(worshipReward);
        // 膜拜日志
        AutoLogMgr.add(new LogCricketWorship(player.getUserId(), worshipReward));
        player.sendPacket(Protocol.U_CRICKET_TOP_RANK_WORSHIP, builder);
        return 0;
    }


    public void addCricketDefense(CricketData cricketData) {
        if (userCricketData == null) {
            return;
        }
        if (userCricketData.getCricketMatchData().getDefenseList().contains(cricketData.getCricketId())) {
            return;
        }
        if (userCricketData.getCricketMatchData().getDefenseList().size() >= GameConfig.CRICKET_FIGHT_DEF_FIT_NUM) {
            return;
        }
        userCricketData.getCricketMatchData().getDefenseList().add(cricketData.getCricketId());
        userCricketData.setUpdateOption();
        // 上传到跨服
        uploadCricketDefenseToCross();
    }

    public int updateCricketDefense(CricketProto.CricketDefenseSetReqMsg reqMsg) {
        if (this.cricketDataMap.size() < GameConfig.CRICKET_FIGHT_DEF_FIT_NUM && reqMsg.getCricketIdList().size() < this.cricketDataMap.size()) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        if (reqMsg.getCricketIdList().size() > GameConfig.CRICKET_FIGHT_DEF_FIT_NUM) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }

        List<CricketData> list = new ArrayList<>();
        for (int cricketId : reqMsg.getCricketIdList()) {
            CricketData cricketData = this.getCricketData(cricketId);
            if (cricketData == null) {
                return GameErrorCode.E_CRICKET_CRICKET_NOT_FOUND;
            }
            list.add(cricketData);
        }
        if (userCricketData == null) {
            return GameErrorCode.E_ERROR_PARAMETER;
        }
        userCricketData.getCricketMatchData().getDefenseList().clear();
        for (CricketData cricketData : list) {
            userCricketData.getCricketMatchData().getDefenseList().add(cricketData.getCricketId());
        }
        userCricketData.setUpdateOption();
        uploadCricketDefenseToCross();
        return 0;
    }

    /**
     * 上传玩家防守阵容到跨服
     */
    public void uploadCricketDefenseToCross() {
        try {
            if (userCricketData.getCricketMatchData().getDefenseList().size() < GameConfig.CRICKET_FIGHT_PLAYER_LIMIT) {
                return;
            }
            player.sendPacket(Protocol.C_CRICKET_COURT_UPDATE_USER_INFO, updateDefenseReqMsg());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 上传玩家勋章到跨服
     */
    public void uploadCricketCourtBadgeToCross() {
        try {
            if (userCricketData.getCourtBadgeId() == 0) {
                return;
            }
            player.sendPacket(Protocol.C_CRICKET_COURT_UPDATE_USER_INFO, updateCourtBadgeReqMsg());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public CricketProto.CricketCourtUpdateUserInfoReqMsg.Builder updateDefenseReqMsg() {
        if (userCricketData == null) {
            return null;
        }
        CricketProto.CricketCourtUpdateUserInfoReqMsg.Builder builder = CricketProto.CricketCourtUpdateUserInfoReqMsg.newBuilder();
        builder.setServerId(GameServer.getInstance().getServerId());
        builder.setUserId(player.getUserId());
        builder.setType(1);
        for (int cricketId : userCricketData.getCricketMatchData().getDefenseList()) {
            CricketBattleData cricketBattleData = toCricketBattleData(cricketId);
            builder.addCricketDefense(cricketBattleData.getCricketMatchDataTemp());
        }
        return builder;
    }


    public CricketProto.CricketCourtUpdateUserInfoReqMsg.Builder updateCourtBadgeReqMsg() {
        if (userCricketData == null) {
            return null;
        }
        CricketProto.CricketCourtUpdateUserInfoReqMsg.Builder builder = CricketProto.CricketCourtUpdateUserInfoReqMsg.newBuilder();
        builder.setServerId(GameServer.getInstance().getServerId());
        builder.setUserId(player.getUserId());
        builder.setType(2);
        builder.setCourtBadgeId(userCricketData.getCourtBadgeId());
        return builder;
    }

    public CricketProto.CricketUserBattleDataTemp.Builder toCricketUserBattleDataTemp() {
        UserCricketData userCricketData = getUserCricketData();
        CricketProto.CricketUserBattleDataTemp.Builder builder = CricketProto.CricketUserBattleDataTemp.newBuilder();
        builder.setUserId(player.getUserId());
        UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(player.getUserId(), GameServer.getInstance().getServerId());
        if (userBaseInfo != null) {
            builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        }
        builder.setScore(userCricketData.getRankScore());
        builder.setCourtBadgeId(userCricketData.getCourtBadgeId());
        return builder;
    }

    public CricketBattleData toCricketBattleData(int cricketId) {
        CricketData cricketData = this.getCricketData(cricketId);
        if (cricketData == null) {
            return null;
        }


        CricketProto.CricketTempMsg.Builder cricketTemp = CricketPb.parseCricketTemp(cricketData);

        CricketProto.CricketMatchDataTemp.Builder cricketMatchDataTemp = CricketPb.parseCricketMatchDataTemp(cricketData);
        List<CricketSkill> allEffectSkill = getAllEffectSkill(cricketData);
        for (CricketSkill cricketSkill : allEffectSkill) {
            CricketProto.CricketSkillTempMsg.Builder cricketSkillTemp = CricketPb.parseCricketSkillTemp(cricketSkill);
            cricketMatchDataTemp.addBattleSkill(cricketSkillTemp);
        }
        cricketMatchDataTemp.addAllAttackSkill(cricketTemp.getAttackSkillList());
        cricketMatchDataTemp.addAllInitSkill(cricketTemp.getInitSkillList());
        cricketMatchDataTemp.addAllSkill(cricketTemp.getSkillList());

        CricketBattleData cricketBattleData = CricketBattleData.getInstance(cricketMatchDataTemp.build());
        return cricketBattleData;
    }


    /**
     * 榜单变更
     */
    private void changeCricketScoreRank() {
        try {
            RankMgr.changeUserRank(eBigRankType.Normal.getValue(), player.getUserId(), BigInteger.valueOf(userCricketData.getCricketScore()), eRankType.CricketScore.getValue(), String.valueOf(userCricketData.getBadgeLevel()));
        } catch (Exception e) {
            log.error(e);
        }
    }

    /*
     * 是否在可以匹配的时间内
     *
     * @return
     */
    public int isMatchOpen() {
        if (cricketDataMap.size() < GameConfig.CRICKET_FIGHT_PLAYER_LIMIT) {
            return GameErrorCode.E_CRICKET_NUM_NOT_ENOUGH;
        }
        if (!courtSystemOpen()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }

        List<List<Integer>> cricketFightOpenTimeList = CricketMgr.getCricketFightOpenTimeList();
        if (cricketFightOpenTimeList.size() == 0) {
            return 0;
        }
        long now = System.currentTimeMillis() / 1000;

        int todayZeroTime = DateHelper.getTodayZeroTime();

        for (List<Integer> list : cricketFightOpenTimeList) {
            if (now >= todayZeroTime + list.get(0) * 60 && now <= todayZeroTime + list.get(1) * 60) {
                return 0;
            }
        }
        return GameErrorCode.E_CRICKET_NOT_MATCH_TIME;
    }

    /**
     * 是否可下单
     *
     * @param mallId
     * @return
     */
    public boolean canPrecharge(int mallId) {
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            return false;
        }
        if(userCricketData == null){
            return false;
        }
        return true;
    }

    public int getBookDataMapSize(){
        if(null == bookDataMap){
            return 0;
        }
        return bookDataMap.size();
    }

    /**
     * 获取竞技场信息
     */
    public int getCourtInfo() {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        if (!courtSystemOpen()) {
            return GameErrorCode.E_CRICKET_COURT_NOT_OPEN;
        }
        // 上跨服
        CricketProto.CrossCricketGetCourtInfoReqMsg.Builder reqMsg = CricketProto.CrossCricketGetCourtInfoReqMsg.newBuilder();
        reqMsg.setUserBaseInfo(PlayerPb.parsePlayerBaseTempMsg(player.getUserInfo()));
        for (int cricketId : userCricketData.getCricketMatchData().getDefenseList()) {
            CricketBattleData cricketBattleData = toCricketBattleData(cricketId);
            reqMsg.addCricketDefense(cricketBattleData.getCricketMatchDataTemp());
        }
        player.sendPacket(Protocol.C_CRICKET_GET_COURT_INFO, reqMsg);
        return 0;
    }

    /**
     * 竞技场信息同步
     */
    public void cricketCourtSyncData() {
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            return;
        }
        CricketProto.CricketCourtDataSyncRespMsg.Builder respMsg = CricketProto.CricketCourtDataSyncRespMsg.newBuilder();
        if (!courtSystemOpen()) {
            // 系统维护
            respMsg.setSystemOpen(false);
            player.sendPacket(Protocol.U_CRICKET_COURT_SYNC_DATA, respMsg);
            return;
        }
        // 上跨服
        syncCrossCricketData();
    }

    /**
     * 获取竞技场宗师场信息
     */
    public int getCourtTopUserData() {
        if (userCricketData == null) {
            return GameErrorCode.E_CRICKET_NOT_OPEN;
        }
        // 上跨服
        CricketProto.CrossCricketCourtGetTopUserDataReqMsg.Builder reqMsg = CricketProto.CrossCricketCourtGetTopUserDataReqMsg.newBuilder();
        player.sendPacket(Protocol.C_CRICKET_COURT_GET_TOP_USER_DATA, reqMsg);
        return 0;
    }

    /**
     * 能否购买战令
     */
    public boolean canRechargeToken(MallInfo mallInfo) {
        // 判断时间
        ActivityInfo activityInfo = CricketMgr.getConfig().getActivityInfo();
        if (!ActivityMgr.activityInShowTime(activityInfo)) {
            return false;
        }
        if (userCricketData == null) {
            return false;
        }
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Cricket.getValue())) {
            return false;
        }
        return !isBuyToken(mallInfo.getShopType());
    }

    public boolean isBuyToken(int shopType) {
        if(userCricketData == null){
            return false;
        }
        if(shopType == eShopType.ChineseChessGoldToken.getValue()){
            return userCricketData.getBuyGoldToken() > 0;
        }
        if(shopType == eShopType.ChineseChessSilverToken.getValue()){
            return userCricketData.getBuySliverToken() > 0;
        }
        return false;
    }

    public void rechargeToken(MallInfo mallInfo) {
        try {
            if (userCricketData == null) {
                return;
            }
            ActivityInfo activityInfo = CricketMgr.getConfig().getActivityInfo();
            if (!ActivityMgr.activityInShowTime(activityInfo)) {
                return;
            }
            BigInteger tokenExp = BigInteger.valueOf(userCricketData.getTokenExp());
            if (mallInfo.getShopType() == eShopType.ChineseChessSilverToken.getValue()) {
                userCricketData.setBuySliverToken(1);
                player.notifyListener(eGamePlayerEventType.CricketCourtSliverToken.getValue(), tokenExp);
            } else if (mallInfo.getShopType() == eShopType.ChineseChessGoldToken.getValue()) {
                userCricketData.setBuyGoldToken(1);
                player.notifyListener(eGamePlayerEventType.CricketCourtGoldToken.getValue(), tokenExp);
            }
            syncUserData();
        } catch (Exception e) {
            logger.error(" {} rechargeToken error, mallId {} ,activityId : {}", player.getUserId(), mallInfo.getMallId(), mallInfo.getActivityId());
        }
    }

    /**
     * 添加战令经验
     * @param count 经验
     */
    public void addTokenExp(BigInteger count) {
        userCricketData.setTokenExp(userCricketData.getTokenExp() + count.longValue());
        player.notifyListener(eGamePlayerEventType.CricketCourtBronzeToken.getValue(), BigInteger.valueOf(userCricketData.getTokenExp()));
        player.notifyListener(eGamePlayerEventType.CricketCourtSliverToken.getValue(), BigInteger.valueOf(userCricketData.getTokenExp()));
        player.notifyListener(eGamePlayerEventType.CricketCourtGoldToken.getValue(), BigInteger.valueOf(userCricketData.getTokenExp()));
    }





    /**
     * 重置战令
     */
    public void resetToken(){
        userCricketData.setTokenExp(0);
        userCricketData.setBuyGoldToken(0);
        userCricketData.setBuySliverToken(0);
        // 重置任务
        player.getModule(ActivityModule.class).resetCricketCourtTokenTask(CricketMgr.getConfig().getActivityInfo().getActivityId());
    }

}